有两个表,
Categories(Id, Name) Products(Id, Text, CategoryId)
还有另一个过滤产品的表格:
Filter(CategoryIds, ContainText)
Filter表中的CategoryIds是逗号分隔的:100,101
我们希望根据从过滤表格中提取的标准来查询产品。
实施例: 过滤器只有两个记录:
CategoryIds | ContainText ----------------------------- 100,101 | A 200,201 | B
以下是我们要查询的产品:
containting text 'B' in categories 200 or 201
或者
FB.init({
appId : '{app-id}',
cookie : true,
version : 'v2.5'
});
我们不想使用动态查询。
感谢您的帮助。
答案 0 :(得分:2)
根据Giorgos的评论,您需要规范化Filter
表。如果你坚持这个设计,这是一个解决方案:
首先,您需要一个字符串拆分器。这是一张取自Aaron Bertrand的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
,Products
和拆分的Categories
表格上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 + '%'
答案 1 :(得分: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
答案 2 :(得分: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)) +',%'
答案 3 :(得分: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)
然后,您可以将此表加入Products
和Categories
:
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 +'%'