2016-04-25 109 views
-1

有兩個表,查詢基於記錄條件

 
Categories(Id, Name) 
Products(Id, Text, CategoryId) 

有用於過濾產品中的另一個表:

 
Filter(CategoryIds, ContainText) 

CategoryIds在過濾器表中的逗號分隔:100101

我們希望根據從Filters表中提取的條件查詢產品。

例: 過濾器只有兩個記錄:

 
CategoryIds | ContainText 
----------------------------- 
100,101  | A 
200,201  | B 

下面是產品,我們要查詢:

containting text 'A' in categories 100 or 101 

或者

containting text 'B' in categories 200 or 201 

我們不希望使用動態查詢。

感謝您的任何幫助。

+0

請發佈樣本數據和預期結果。 –

+7

你的'過濾器'表需要正常化。像這樣存儲逗號分隔的值是一個非常糟糕的主意。 –

+0

如果你有任何想法正常化過濾表請提示我。 –

回答

2

根據Giorgos的評論,您需要規範化您的Filter表。如果你堅持這種設計,這裏有一個解決方案:

首先,你需要有一個字符串拆分器。下面是阿龍貝特朗的article採取一個:

CREATE FUNCTION dbo.SplitStrings_XML 
(
    @List  NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    ( 
     SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)') 
     FROM 
     ( 
     SELECT x = CONVERT(XML, '<i>' 
      + REPLACE(@List, @Delimiter, '</i><i>') 
      + '</i>').query('.') 
    ) AS a CROSS APPLY x.nodes('i') AS y(i) 
    ); 

然後,你需要在你Filter表分割成單獨行。然後做JOIN S於該ProductsCategories和分裂Filter表:

WITH CteFilter(CategoryId, ContainText) AS(
    SELECT 
     CAST(s.Item AS INT), f.ContainText 
    FROM Filter f 
    CROSS APPLY dbo.SplitStrings_XML(f.CategoryIds, ',') s 
) 
SELECT p.* 
FROM Products p 
INNER JOIN Categories c 
    ON c.Id = p.CategoryId 
INNER JOIN CteFilter f 
    ON f.CategoryId = c.Id 
    AND p.Text LIKE '%' + f.ContainText + '%' 
+0

非常感謝。我測試了它,它工作。 –

+0

@JafarElahi沒問題。如果你可以規範你的桌子,我建議你這樣做。 –

1

假設正常化是可能的,這裏是一個簡單的查詢,將這樣的伎倆:

創建示例表:

DECLARE @Categories as table 
(
    id int identity(1,1), 
    name char(1) 
) 

DECLARE @Products as table 
(
    id int identity(1,1), 
    name varchar(100), 
    categoryId int 
) 

DECLARE @Filter as table 
(
    id int identity(1,1), 
    ContainText varchar(100) 
) 

DECLARE @FilterCategories as table 
(
    FilterId int, 
    CategoryId int, 
    PRIMARY KEY(filterId, CategoryId) 
) 

填充樣本表:

INSERT INTO @Categories 
VALUES ('A'),('B'),('C'),('D'),('E') 

INSERT INTO @Products (name, categoryId) 
VALUES ('cat A', 1),('category A', 1), ('cat B', 2), ('category B', 2) 

INSERT INTO @Filter 
VALUES ('gory'), ('cat') 

INSERT INTO @FilterCategories 
VALUES (1, 1), (1, 2), (2, 1) 

查詢:

SELECT DISTINCT p.id As ProductId, 
     p.name As ProductName, 
     c.name As CategoryName 
FROM @Filter f 
INNER JOIN @FilterCategories fc ON(f.id = fc.FilterId) 
INNER JOIN @Products p ON(p.categoryId = fc.CategoryId) 
INNER JOIN @Categories c ON(p.categoryId = c.id) 
WHERE p.name LIKE '%'+ f.ContainText +'%' 

結果:

ProductId ProductName     CategoryName 
----------- ------------------------------ ------------ 
1   cat A       A 
2   category A      A 
4   category B      B 
+0

您的填寫數據比我快。謝謝。 –

0

爲了歸Filters表,你可以使用這樣的事情:

DECLARE @xml xml 

;WITH Filters AS (
SELECT * 
FROM (VALUES 
('100,101', 'A'), 
('200,201', 'B'), 
('300,301,302', 'C') 
) as t(CategoryIds, ContainText) 
) 

SELECT @xml =(
SELECT CAST ('<b>' + ContainText + '<a>'+REPLACE(CategoryIds,',','</a><a>') + '</a></b>' as xml) 
FROM Filters 
FOR XML PATH('') 
) 

SELECT t.v.value('../.','nvarchar(1)') as ContainText, 
     t.v.value('.','int') as CategoryId 
FROM @xml.nodes('/b/a') as t(v) 

輸出:

ContainText CategoryId 
----------- ----------- 
A   100 
A   101 
B   200 
B   201 
C   300 
C   301 
C   302 

(7 row(s) affected) 

然後你就可以加入這個表ProductsCategories

SELECT * 
FROM NormFilters nf 
INNER JOIN Categories c -- (Id, Name) 
    ON nf.CategoryId = c.Id 
INNER JOIN Products p --(Id, Text, CategoryId) 
    ON c.CategoryId = p.CategoryId AND p.[Text] LIKE '%' + nf.ContainText +'%' 
1

您也可以嘗試下面的查詢不需要正常化。因此,如果您無法更新您的表格,請嘗試以下簡單的查詢:JOIN

--create table categories(id int, name varchar(100)); 
--create table products(id int, text varchar(100), categoryid int); 
--create table filters(categoryids varchar(100), containtext varchar(10)); 
--insert into filters values 
--('100,101','A'), 
--('200,201','B'); 
--insert into products values 
--(1,'Random',100), 
--(2,'rps',101), 
--(3,'rps',200), 
--(4,'rpsb',201); 
--insert into categories values 
--(100,'Cat100'), 
--(101,'Cat101'), 
--(200,'Cat200'), 
--(201,'Cat201'); 

select 
    P.*,C.Name 
from Products P join Categories C 
     on C.Id=P.CategoryId 
join Filters F 
    on text like '%'+ContainText+'%' 
      and ','+ CategoryIds +',' like '%,'+cast(C.ID as varchar(100)) +',%' 
+0

好方法!但我認爲性能不高效。因爲產品表是一個大表,它的字符串操作實際上會很低。 –

+0

@JafarElahi當我們將類別id存儲爲int的規範化表格進行比較時,性能將低於標準差。但是,如果你堅持設計,你可能會走這條路。查詢花費了4秒鐘在我的機器上運行了一百萬行。 – DhruvJoshi