2011-09-20 19 views
12

में आईडी की सीएसवी सूची में सभी मानों से मेल खाते हैं, मैंने एक सरल उदाहरण बनाया है (उम्मीद है कि मेरे वास्तविक डेटा से अधिक मजेदार) मेरे व्यक्तित्व को बेहतर व्यक्त करने के लिए प्रश्न:मैं केवल उन पंक्तियों को देने के लिए एक क्वेरी तैयार कर सकता हूं जो टी-एसक्यूएल

CREATE TABLE SUPER_HERO 
( ID INT, 
    NAME VARCHAR(50) 
) 

INSERT INTO SUPER_HERO VALUES (1, 'Storm') 
INSERT INTO SUPER_HERO VALUES (2, 'Silver Surfer') 
INSERT INTO SUPER_HERO VALUES (3, 'Spider Man') 

CREATE TABLE SKILL 
( ID INT, 
    NAME VARCHAR(50) 
) 

INSERT INTO SKILL VALUES (1, 'Flight') 
INSERT INTO SKILL VALUES (2, 'Weather Control') 
INSERT INTO SKILL VALUES (3, 'Super Speed') 

CREATE TABLE SUPER_HERO_SKILL 
( SUPER_HERO_ID INT, 
    SKILL_ID INT 
) 

INSERT INTO SUPER_HERO_SKILL VALUES (1, 1) --Storm has Flight 
INSERT INTO SUPER_HERO_SKILL VALUES (1, 2) --Storm has Weather Control 
INSERT INTO SUPER_HERO_SKILL VALUES (2, 1) --Silver Surfer has Flight 
INSERT INTO SUPER_HERO_SKILL VALUES (2, 3) --Silver Surfer has Super Speed 
INSERT INTO SUPER_HERO_SKILL VALUES (3, 3) --Spider Man has Super Speed 

बुरा क्वेरी (वांछित परिणाम नहीं दिखा रहा है) का उदाहरण:

DECLARE @DELIMITER CHAR = ',' 
DECLARE @CSV_STRING VARCHAR(20) = '1,3' 

SELECT 
    SUPER_HERO_NAME = SUPER_HERO.NAME, 
    SKILL_NAME  = SKILL.NAME 
FROM 
    SUPER_HERO 
    JOIN SUPER_HERO_SKILL ON SUPER_HERO_SKILL.SUPER_HERO_ID = SUPER_HERO.ID 
    JOIN SKILL ON SUPER_HERO_SKILL.SKILL_ID = SKILL.ID 
    JOIN dbo.Split(@CSV_STRING, @DELIMITER) SPLIT ON SPLIT.ITEMS = SKILL.ID 

मैं चाहते हैं क्या देखने के लिए:
जब DECLARE @CSV_STRING VARCHAR(20) = '1,3' मैं केवल इसे ही देख "रजत Surfer" si एनसी वह कौशल 1 और 3 दोनों के साथ एकमात्र ऐसा है जो फ्लाइट और सुपर स्पीड से संबंधित है।

जब DECLARE @CSV_STRING VARCHAR(20) = '1,2,3' मुझे किसी भी मेरे ब्रह्मांड में नायकों को नहीं देखना चाहिए क्योंकि कोई भी तीन कौशल सूचीबद्ध नहीं है।


कुछ सरल है कि मुझे याद आ रही होनी चाहिए। मैंने क्वेरी को कई अलग-अलग तरीकों से ढंकने की कोशिश की है। मैंने समस्या का प्रस्तुति जटिल नहीं करने के लिए यहां इसका सबसे सरल रूप प्रस्तुत किया है।

नोट:। मैं एक समारोह है कि सीमांकक में पारित के आधार पर एक Split रूप में कार्य करता का उपयोग

+1

वाह क्या एक आश्चर्यजनक अच्छा प्रश्न है। इस के जवाब में रूचि है। –

+1

आपके उदाहरण में सुपर हीरो का उपयोग करने के लिए +1 =) –

उत्तर

6

नीचे स्प्लिटर समारोह जो किसी पूर्णांक स्तंभ रिटर्न का प्रयोग करें। इसलिए हैविंग क्लॉज में गिनती की जांच करना आसान है।

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 

यह काम करता है, अंत में अतिरिक्त कॉमा देने के लिए ध्यान रखें।

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

यह मेरे अन्य प्रयासों में से एक था, लेकिन कुछ कारणों से विभाजित वस्तुओं की अलग-अलग गिनती का उपयोग करके सुपर हीरो आईडी के अलग-अलग गिनती के परिणामस्वरूप * नहीं * पंक्तियां लौट आईं। यह * ऐसा करने का सही तरीका लगता है लेकिन मैं इसे काम करने के लिए नहीं मिल सकता। – Gibron

+0

विभिन्न इनपुट के साथ प्रयास किया और अभी जवाब को फिर से अपडेट किया। अभी ठीक काम करता है। – CharithJ

+0

आप रॉक! समूह के साथ उप-चयन यह था! यह आश्चर्यजनक है कि आप इस तरह के सरल समाधानों के साथ इतनी देर तक कितनी चीजें देखते हैं। बहुत बहुत धन्यवाद! :) – Gibron

1

यह दो भागों, फिल्टर, और क्वेरी के बाकी हिस्सों में बांटा गया है, तो यह आसान है का विस्तार करने के

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

मुझे यह समाधान भी पसंद है। धन्यवाद! :) – Gibron

संबंधित मुद्दे

 संबंधित मुद्दे