SQL Server How to write a SQL query if I want to get value with multiple codes in single column?

qybjjes1  于 2023-11-16  发布在  其他
关注(0)|答案(1)|浏览(151)

I have a column name Generic_Code in a SQL Server table FAMPRD .

This column has values like '00001' . Sometimes column has values like '00001', '00002' . And sometimes like this '00001', '00002', '00034', '00052' in a single cell value.

Here is a sample data of my table:
| Prd_Code | Prd_Desc1 | Packing | Company_Name | Generic_Code |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| 701010001 | NIXIDE-500 TAB | 110 | MEDLEY PHARMA.PVT.LTD. | '00001','00002' |
| 701010013 | CASH | 1 | 7 CLOCK | '00001', '00002', '00034', '00052' |
| 701010016 | LIQUID PARAFIN 100ML | 1
100ML | COMMON PRODUCT | '00003' |
| 701010017 | NAPZAC EYE DROP | | 7 CLOCK | '00001' |
| 701010018 | NCIN | | 7 CLOCK | '00001' |
| 701010019 | REG-MPS TAB | 10 TAB | 7 CLOCK | '00001' |
| 701010020 | S | | 7 CLOCK | '00001' |
| 701010021 | EDARABID INJ | 120ML | INTAS PHRMA. | '00001' |
| 701010022 | GLOSILK SOAP | 1
75GM | AARISE BIOCARE PVT | '00001' |

Column data types

All columns are varchar .

Now I have 2 questions:

Question #1

I want write a SQL query where if I want to search '00001', '00002' then all data which includes '00001' and '00002' should be returned.

It's like a strict filter that if and only if value '00001' and '00002' exists then return that data but if exists more than that it won't return.

Example:

  • Only get data when only '00001' and '00002' exists.
  • If value is '00001', '00002', '00034', '00052' then not needed.

Expected result:
| Prd_Code | Prd_Desc1 | Packing | Company_Name | Generic_Code |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| 701010001 | NIXIDE-500 TAB | 1*10 | MEDLEY PHARMA.PVT.LTD. | '00001','00002' |

Question #2

Another query I want to write is if I search for '00001', '00002' then all data which includes '00001' or '00002' should be returned. It should fetch all data if 00001 or 00002 exists in any data.

Expected result :
| Prd_Code | Prd_Desc1 | Packing | Company_Name | Generic_Code |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| 701010001 | NIXIDE-500 TAB | 110 | MEDLEY PHARMA.PVT.LTD. | '00001','00002' |
| 701010013 | CASH | 1 | 7 CLOCK | '00001', '00002', '00034', '00052' |
| 701010017 | NAPZAC EYE DROP | | 7 CLOCK | '00001' |
| 701010018 | NCIN | | 7 CLOCK | '00001' |
| 701010019 | REG-MPS TAB | 10 TAB | 7 CLOCK | '00001' |
| 701010020 | S | | 7 CLOCK | '00001' |
| 701010021 | EDARABID INJ | 1
20ML | INTAS PHRMA. | '00001' |
| 701010022 | GLOSILK SOAP | 1*75GM | AARISE BIOCARE PVT | '00001' |

Thanks in advance.

j9per5c4

j9per5c41#

Firstly, I'd advise a read of this: Is storing a delimited list in a database column really that bad? (Spoiler, the answer is yes).

Next I'd advise a read of Divided We Stand: The SQL of Relational Division , this covers a wide range of approaches to relational division (what you are trying to do) for each of the scenarios you've covered.

Finally, the approach I would take is to first split your values into rows using STRING_SPLIT then do your equality checks, then roll these back up to the original row level, something like:

DECLARE @Values VARCHAR(1000) = '00001,00002';
WITH SplitInput AS
(
    SELECT  DISTINCT ss.value
    FROM    STRING_SPLIT(@Values, ',') AS ss
)
SELECT sd.GenericCode,
        ContainsAny = CASE WHEN COUNT(si.value) > 0 THEN 1 ELSE 0 END,
        ContainsAll = CASE WHEN COUNT(si.value) = (SELECT COUNT(*) FROM SplitInput) THEN 1 ELSE 0 END,
        ContainsOnly = CASE WHEN COUNT(si.value) = COUNT(*) AND COUNT(si.value) = (SELECT COUNT(*) FROM SplitInput) THEN 1 ELSE 0 END
FROM    #SampleData AS sd
        CROSS APPLY STRING_SPLIT(sd.GenericCode, ',') AS ss
        LEFT JOIN SplitInput AS si
            ON si.value = ss.value
GROUP BY sd.GenericCode;

For a sample data set this returns something like the following for the input above (00001,00002)

GenericCodeContainsAnyContainsAllContainsOnly
00001100
00001,00002111
00001,00002,00034110
00052000
  • Contains Any = Any of the supplied values match any of the values stored
  • Contains All = All of the supplied values match the stored values, does not matter if there are additional stored values
  • Contains Only = All of the supplied values are matched with no remainder (i.e. exact match)

Hopefully you can adapt this to suit your different scenarios.

Full Code example

DROP TABLE IF EXISTS #SampleData;
CREATE TABLE #SampleData (GenericCode VARCHAR(100));
INSERT #SampleData(GenericCode)
VALUES ('00001'),('00001,00002'),('00001,00034'), ('00001,00002,00034,00052');
GO
DROP PROCEDURE IF EXISTS #SampleProcedure; -- Using temp proc for simplicity of demo code
GO
CREATE PROCEDURE #SampleProcedure @Values VARCHAR(1000)
AS
BEGIN
    WITH SplitInput AS
    (
        SELECT  DISTINCT ss.value
        FROM    STRING_SPLIT(@Values, ',') AS ss
    )
    SELECT sd.GenericCode,
            ContainsAny = CASE WHEN COUNT(si.value) > 0 THEN 1 ELSE 0 END,
            ContainsAll = CASE WHEN COUNT(si.value) = (SELECT COUNT(*) FROM SplitInput) THEN 1 ELSE 0 END,
            ContainsOnly = CASE WHEN COUNT(si.value) = COUNT(*) AND COUNT(si.value) = (SELECT COUNT(*) FROM SplitInput) THEN 1 ELSE 0 END
    FROM    #SampleData AS sd
            CROSS APPLY STRING_SPLIT(sd.GenericCode, ',') AS ss
            LEFT JOIN SplitInput AS si
                ON si.value = ss.value
    GROUP BY sd.GenericCode;

END
GO
EXECUTE #SampleProcedure @Values = '00001';
EXECUTE #SampleProcedure @Values = '00001,00002';
EXECUTE #SampleProcedure @Values = '00001,00002,00034';
EXECUTE #SampleProcedure @Values = '00001,00002,00034,00052';
EXECUTE #SampleProcedure @Values = '00035,00055';

相关问题