2013-08-16 6 views
8

मैं उस कैलेंडर सेवा के भीतर कैलेंडर सेवा बनाने का प्रयास कर रहा हूं, घटनाएं हैं, और घटनाओं को मेटाडेटा के साथ टैग किया जा सकता है जो खोजने योग्य है।एसक्यूएल चयन करें जहां टैग मूल्य LIKE

मैं उन रिकॉर्ड्स की खोज करने में सक्षम होना चाहता हूं जहां सभी टैग मौजूद हैं (अनिवार्य टैग) और/या जहां कोई टैग मौजूद है (वैकल्पिक टैग)।

मैं एक क्वेरी बनाने में कामयाब रहा हूं जहां यह काम करता है, जब टैग मान 'बिल्कुल' से मेल खाता है। लेकिन मैं उन परिणामों को वापस कैसे कर सकता हूं जहां टैग मूल्य '% value%' जैसा है, मैं काम नहीं कर सकता।

यहाँ मेरी वर्तमान कार्यान्वयन

टेबल्स डाटा

CREATE TABLE Events 
(
Id INT, 
EventText VARCHAR(500) 
); 

CREATE TABLE EventDates 
(
Id INT, 
EventId INT, 
StartDate DATETIME, 
EndDate DATETIME, 
Archived BIT 
); 

CREATE TABLE Tags 
(
Id INT, 
Description VARCHAR(50) 
); 

CREATE TABLE EventTags 
(
EventId INT, 
TagId INT, 
Value VARCHAR(50) 
); 

INSERT INTO Events VALUES (1, 'Event Name 1'); 
INSERT INTO Events VALUES (2, 'Event Name 2'); 

INSERT INTO EventDates VALUES (1, 1, '2013-01-01', '2013-01-02', 0); 
INSERT INTO EventDates VALUES (2, 1, '2013-01-07', '2013-01-08', 0); 
INSERT INTO EventDates VALUES (3, 2, '2013-01-02', '2013-01-03', 0); 

INSERT INTO Tags VALUES (1, 'Tag Name 1'); 
INSERT INTO Tags VALUES (2, 'Tag Name 2'); 

INSERT INTO EventTags VALUES (1, 1, 'Value 1'); 
INSERT INTO EventTags VALUES (1, 1, 'Value 2'); 
INSERT INTO EventTags VALUES (1, 2, 'Value 1'); 
INSERT INTO EventTags VALUES (1, 2, 'Value 2'); 
INSERT INTO EventTags VALUES (2, 1, 'Value 1'); 

क्वेरी

DECLARE @MandatoryTagXml XML 
DECLARE @OptionalTagXml XML 
DECLARE @StartDate DATETIME 
DECLARE @EndDate DATETIME 
DECLARE @SearchTypeId SMALLINT 

SET @StartDate = '2013-01-01' 
SET @EndDate = '2013-01-31' 
SET @SearchTypeId = 1 

-- Tags that it must match all of 
SET @MandatoryTagXml = '<tags> 
          <tag> 
          <description>Tag Name 1</description> 
          <value>Value 1</value> 
          </tag> 
         </tags>' 

-- Tags that it can match one or more of 
SET @OptionalTagXml = '<tags> 
          <tag> 
          <description>Tag Name 2</description> 
          <value>Value 2</value> 
          </tag> 
         </tags>' 

    DECLARE @MandatoryIdTable TABLE ([EventId] BIGINT, [EventDateId] BIGINT) 
    DECLARE @OptionalIdTable TABLE ([EventId] BIGINT, [EventDateId] BIGINT) 

IF(@MandatoryTagXml IS NOT NULL) 
BEGIN 
    -- Select ids with matching mandatory tags. 
    ;WITH MandatoryTags AS 
    (
     SELECT TagValue.value('(./value)[1]', 'nvarchar(100)') AS value, 
      TagValue.value('(./description)[1]', 'nvarchar(100)') AS [description]  
     FROM @MandatoryTagXml.nodes('/tags/tag') AS T(TagValue) 
    ) 

    INSERT INTO @MandatoryIdTable 
    -- Records where ALL tags match EXACTLY 
    SELECT E.Id [EventId], ED.Id [EventDateId] 
    FROM [dbo].[Events] E 
    INNER JOIN [dbo].[EventDates] ED ON ED.EventId = E.Id 
    WHERE ED.StartDate >= @StartDate 
    AND ED.EndDate <= @EndDate 
    AND ED.Archived = 0 
    AND NOT EXISTS (
        SELECT T.Id, c.value 
        FROM MandatoryTags c JOIN Tags T 
         ON c.[description] = T.[Description] 
        EXCEPT 
        SELECT T.TagId, T.Value 
        FROM [EventTags] T 
        WHERE T.EventId = E.Id       
        ) 
END 
ELSE -- Select All records 
BEGIN 
    INSERT INTO @MandatoryIdTable 
    -- Records where ALL tags match EXACTLY 
    SELECT E.Id [EventId], ED.Id [EventDateId] 
    FROM [dbo].[Events] E 
    INNER JOIN [dbo].[EventDates] ED ON ED.EventId = E.Id 
    WHERE ED.StartDate >= @StartDate 
    AND ED.EndDate <= @EndDate 
    AND ED.Archived = 0 
END 

    ;WITH OptionalTags AS 
    (
     SELECT TagValue.value('(./value)[1]', 'nvarchar(100)') AS value, 
      TagValue.value('(./description)[1]', 'nvarchar(100)') AS [description]  
     FROM @OptionalTagXml.nodes('/tags/tag') AS T(TagValue) 
    ) 

    INSERT INTO @OptionalIdTable 
    -- Records ANY tags match EXACTLY 
    SELECT E.Id [EventId], ED.Id [EventDateId] 
    FROM [dbo].[Events] E 
    INNER JOIN [dbo].[EventDates] ED ON ED.EventId = E.Id 
    WHERE ED.StartDate >= @StartDate 
    AND ED.EndDate <= @EndDate 
    AND ED.Archived = 0 
    AND EXISTS (
       SELECT T.Id, c.value 
       FROM OptionalTags c JOIN Tags T 
        ON c.[description] = T.[Description] 
       INTERSECT 
       SELECT T.TagId, T.Value 
       FROM [EventTags] T 
       WHERE T.EventId = E.Id       
       ) 

-- Determine if we need to factor in optional tags in result set 
IF (@OptionalTagXml IS NOT NULL) 
BEGIN 
    -- Select results that exist in both optional and mandatory tables 
    SELECT DISTINCT M.* 
    FROM @MandatoryIdTable M 
    INNER JOIN @OptionalIdTable O ON O.EventId = M.EventId AND O.EventDateId = M.EventDateId 
END 
ELSE 
BEGIN 
    -- Select results that exist in mandatory table 
    SELECT DISTINCT M.* 
    FROM @MandatoryIdTable M 
END 

मैं इसके लिए एक SQLFiddle Demo बनाया है है और।

मेरा विचार सटीक मिलान खोज और मिलान खोज के बीच स्विच करने के लिए @SearchTypeId का उपयोग करना है।

(ध्यान दें मैं एक डीबीए नहीं कर रहा हूँ, इसलिए वहाँ यह करने के लिए बेहतर तरीके हो सकता है। मैं सुझाव के लिए खुले हूँ)

किसी को भी सुझाव कैसे की तरह टैग मूल्यों पर से मेल खाता प्राप्त करने के लिए के रूप में दे सकते हैं?

बहुत धन्यवाद

+3

+1। प्रत्येक एसक्यूएल प्रश्न यह होना चाहिए! –

उत्तर

0

chucknelson मुझे वह प्रोडक्ट दिया जो मुझे करने के लिए आवश्यक था।

इस अनुभाग जोड़ना मूल्य पर एक तरह मैच हो जाता है:

JOIN EventTags ET 
      ON C.[Value] LIKE '%' + ET.Value + '%' 

So, for example, the mandatory section becomes: 

    -- Select ids with matching mandatory tags. 
    ;WITH MandatoryTags AS 
    (
     SELECT TagValue.value('(./value)[1]', 'nvarchar(100)') AS value, 
      TagValue.value('(./description)[1]', 'nvarchar(100)') AS [description]  
     FROM @MandatoryTagXml.nodes('/tags/tag') AS T(TagValue) 
    ) 

    INSERT INTO @MandatoryIdTable 
    -- Records where ALL tags match EXACTLY 
    SELECT E.Id [EventId], ED.Id [EventDateId] 
    FROM [dbo].[Events] E 
    INNER JOIN [dbo].[EventDates] ED ON ED.EventId = E.Id 
    WHERE ED.StartDate >= @StartDate 
    AND ED.EndDate <= @EndDate 
    AND ED.Archived = 0 
    AND NOT EXISTS (
        SELECT T.Id, c.value 
        FROM MandatoryTags c 
        JOIN Tags T 
         ON c.[description] = T.[Description] 
-- Add LIKE match on value 
        JOIN EventTags ET 
         ON C.[Value] LIKE '%' + ET.Value + '%' 
        EXCEPT 
        SELECT T.TagId, T.Value 
        FROM [EventTags] T 
        WHERE T.EventId = E.Id 
        ) 

यह मेरे जैसे मैच करने की अनुमति देता है, और एक @SearchType पैरामीटर का उपयोग कर, मैं या तो मूल प्रश्न चला सकते हैं, या यह एक संशोधन तदनुसार। एसक्यूएल फिल्ड डेमो के लिए

1

मुझे लगता है कि झंडा/स्विच के कुछ प्रकार का उपयोग कर के अपने विचार बदलने के लिए मिलान प्रकार काम करेंगे। मैंने इसे आईडी के बजाय शब्दों का उपयोग करके कार्यान्वित किया, लेकिन यदि आप खोज प्रकार के आधार पर शामिल स्थिति को टॉगल करते हैं, तो आपको अपेक्षित के रूप में मिलान करना चाहिए।

फिडल: http://sqlfiddle.com/#!3/d9fbd/3/0

मैं पहली बार एक टैग है कि 1 टैग करने के लिए समान था और परीक्षण के लिए घटना 2 करने के लिए इसे संलग्न गयी।

INSERT INTO Tags VALUES (3, 'Different Tag Name 1'); 
INSERT INTO EventTags VALUES (2, 3, 'Value 3'); 

मैंने फिर खोज प्रकार ध्वज/स्विच बनाया।

DECLARE @SearchType NVARCHAR(10) 
SET @SearchType = 'LIKE' --other type is EXACT 

तो अब आप उस ध्वज के आधार पर EXISTS शामिल स्थिति को टॉगल कर सकते हैं। मैंने अपनी समझ के लिए अपने पूर्वजों को EXISTS में बदल दिया है। उदाहरण के रूप में अनिवार्य टैग ब्लॉक का उपयोग करके, नई जुड़ी स्थिति नीचे दी गई है।

-- Select ids with matching mandatory tags. 
;WITH MandatoryTags AS 
(
    SELECT TagValue.value('(./value)[1]', 'nvarchar(100)') AS value, 
     TagValue.value('(./description)[1]', 'nvarchar(100)') AS [description]  
    FROM @MandatoryTagXml.nodes('/tags/tag') AS T(TagValue) 
) 

INSERT INTO @MandatoryIdTable 
-- Records where ALL tags match EXACTLY or LIKE 
SELECT E.Id [EventId], ED.Id [EventDateId] 
FROM [dbo].[Events] E 
INNER JOIN [dbo].[EventDates] ED ON ED.EventId = E.Id 
WHERE ED.StartDate >= @StartDate 
AND ED.EndDate <= @EndDate 
AND ED.Archived = 0 
AND EXISTS (
       -- Just care about tag IDs here, not the values 
       SELECT T.Id 
       FROM MandatoryTags c JOIN Tags T 
        ON (
         -- Toggle join type based on flag/switch 
         (@SearchType = 'EXACT' AND c.[description] = T.[Description]) 
         OR 
         (@SearchType = 'LIKE' AND T.[Description] LIKE ('%' + c.[description] + '%')) 
        ) 
       INTERSECT 
       SELECT T.TagId 
       FROM [EventTags] T 
       WHERE T.EventId = E.Id       
       ) 

मुझे यकीन है कि कुछ फिर से फैक्टरिंग और अनुकूलन आप इस एसक्यूएल में कुछ नहीं कर सकता है, लेकिन यह कम से कम आप कैसे अगर वांछित मिलान की तरह करने के लिए पर एक विचार देना चाहिए। आशा करता हूँ की ये काम करेगा!

+0

प्रतिक्रिया के लिए धन्यवाद, यह एक अच्छा विचार है, लेकिन यह मूल्य के बजाय टैग विवरण पर एक समान मिलान कर रहा है। मैंने टैग मूल्य का उपयोग करके एक समान कार्यान्वयन को देखने की कोशिश की, लेकिन दुर्भाग्य से मैं नहीं देख सकता कि यह कैसे काम करेगा। – Yetiish

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