How can I structure a query to give me only the rows that match ALL values in a CSV list of IDs in T-SQL

前端 未结 2 1249
日久生厌
日久生厌 2020-12-06 06:02

I\'ve created a simple example (hopefully much more fun than my actual data) to better express my question:

CREATE TABLE SUPER_HERO
(   ID INT,
    NAME VAR         


        
相关标签:
2条回答
  • 2020-12-06 06:22

    Use the below splitter function which returns an int column. So it's easy to check the count in the HAVING clause.

    CREATE FUNCTION [dbo].[DelimitedParamParser]( @DelimitedIds VARCHAR(MAX), @Delimiter CHAR(1)) 
    RETURNS @IdsTable 
    TABLE ( Id INT ) 
    AS BEGIN
    
    DECLARE @Length INT,
            @Index INT,
            @NextIndex INT
    
    SET @Length = DATALENGTH(@DelimitedIds)
    SET @Index = 0
    SET @NextIndex = 0
    
    
    WHILE (@Length > @Index )
    BEGIN
        SET @NextIndex = CHARINDEX(@Delimiter, @DelimitedIds, @Index)
        IF (@NextIndex = 0 ) SET @NextIndex = @Length + 2
            INSERT @IdsTable SELECT SUBSTRING( @DelimitedIds, @Index, @NextIndex - @Index )
        SET @index = @nextindex + 1
    END
     RETURN
    END
    

    This works, keep in mind to give an extra comma at the end.

    DECLARE @DELIMITER CHAR = ','
    DECLARE @CSV_STRING VARCHAR(20) = '1,3,'
    
    SELECT Distinct SUPER_HERO.NAME, SKILL.NAME
    FROM 
        SUPER_HERO
        INNER JOIN SUPER_HERO_SKILL ON  SUPER_HERO_SKILL.SUPER_HERO_ID = SUPER_HERO.ID
        INNER JOIN SKILL ON SUPER_HERO_SKILL.SKILL_ID = SKILL.ID
        WHERE SUPER_HERO.ID IN
        (
        SELECT SUPER_HERO_SKILL.SUPER_HERO_ID   
        FROM 
            SUPER_HERO
            INNER JOIN SUPER_HERO_SKILL ON  SUPER_HERO_SKILL.SUPER_HERO_ID = SUPER_HERO.ID
            INNER JOIN SKILL ON SUPER_HERO_SKILL.SKILL_ID = SKILL.ID
            INNER JOIN DelimitedParamParser(@CSV_STRING, @DELIMITER) SPLIT  ON SPLIT.ID = SUPER_HERO_SKILL.SKILL_ID
        GROUP BY SUPER_HERO_SKILL.SUPER_HERO_ID
        HAVING COUNT(DISTINCT(SUPER_HERO_SKILL.SKILL_ID)) = (SELECT COUNT(DISTINCT(Id)) FROM DelimitedParamParser(@CSV_STRING, @DELIMITER))
        )
    
    0 讨论(0)
  • 2020-12-06 06:41

    This is divided in two parts, the filter, and the rest of the query so it is easy to extend

    DECLARE @DELIMITER CHAR = ','
    DECLARE @CSV_STRING VARCHAR(20) = '1,3'
    
    SELECT @TOTREQ = COUNT(DISTINCT ITEMS) FROM dbo.Split(@CSV_STRING, @DELIMITER)
    
    SELECT 
         SUPER_HERO_NAME =   SUPER_HERO.NAME
    FROM 
        SUPER_HERO INNER JOIN
        (SELECT SUPER_HERO_SKILL.SUPER_HERO_ID
         FROM SUPER_HERO_SKILL     
         LEFT JOIN dbo.Split(@CSV_STRING, @DELIMITER) SPLIT ON SUPER_HERO_SKILL.SKILL_ID = SPLIT.ITEMS
         GROUP BY SUPER_HERO_SKILL.SUPER_HERO_ID
         HAVING COUNT(SPLIT.ITEMS) = @TOTREQ      -- This ensure no mising super-powers
            AND COUNT(*) = @TOTREQ                -- This ensure no extra super-powers  (can be omited of course)
         ) AS FILTER ON     SUPER_HERO.ID = FILTER.SUPER_HERO_ID
    
    0 讨论(0)
提交回复
热议问题