我正在开发一个搜索工具,我需要使用最多6个搜索参数搜索表格,问题是,6个参数中的5个需要搜索同一列。
我正在搜索从item_category
表填充的临时表,此临时表有3列,item
,item_desc
和cat_desc
。第一个搜索参数为@Desc
,此parm将搜索item_desc
列,其他5个参数为@P1
,@P2
,@P3
,{{1} }和@P4
,都是@P5
种类型。这些nvarchar(40)
个参数都需要搜索@P#
列。
下面是创建包含示例数据的临时表的代码,以及我到目前为止的查询代码。我尝试用注释解释每个部分,我将在下面解释代码我需要它做什么。
cat_desc
我们的商品可以链接到多个类别,此查询的目标是能够按最多五个不同的类别搜索商品,按商品描述加上,因此查询参数-- Create Temp Tables --
CREATE TABLE #Item_Category_List(
item nvarchar(30)
,item_desc nvarchar(40)
,cat_desc nvarchar(40));
-- Populate #Item_Category_List with sample data
INSERT #Item_Category_List(item, item_desc, cat_desc)
VALUES ('2-77132', '2-77132 P1812-24-120', 'Keypad PB Controls W/Variable Speed')
,('2-77132', '2-77132 P1812-24-120', '60 Hertz')
,('2-77132', '2-77132 P1812-24-120', '1 x 3.00HP Motor')
,('2-77132', '2-77132 P1812-24-120', 'Light Curtain Option')
,('2-77132', '2-77132 P1812-24-120', 'Bin Detection Option')
,('2-77132', '2-77132 P1812-24-120', '3 Phase')
,('2-77132', '2-77132 P1812-24-120', '480 Volts')
,('2-70470', 'CANTILEVER-CRSL-C20243-3912-194', 'Vidir Inventory Control Software')
,('2-70470', 'CANTILEVER-CRSL-C20243-3912-194', '60 Hertz')
,('2-70470', 'CANTILEVER-CRSL-C20243-3912-194', 'SEW Motor')
,('2-70470', 'CANTILEVER-CRSL-C20243-3912-194', '3 Phase')
,('2-70470', 'CANTILEVER-CRSL-C20243-3912-194', '460 Volts')
,('2-77562', 'HT54193-0663-12-RAMP', 'Keypad PB Controls W/Variable Speed')
,('2-77562', 'HT54193-0663-12-RAMP', '60 Hertz')
,('2-77562', 'HT54193-0663-12-RAMP', 'Top Right Side Front Location')
,('2-77562', 'HT54193-0663-12-RAMP', '2 x 2.00HP Motor')
,('2-77562', 'HT54193-0663-12-RAMP', '3 Phase')
,('2-77562', 'HT54193-0663-12-RAMP', '208 Volts')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', '2 Hand Security Control')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', 'Keypad PB Controls')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', '50 Hertz')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', 'Right Side Front Location')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', '1 x 1.50HP Motor')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', '1 Phase')
,('2-76559', 'R20116-1416-4M 2-HAND CONTROLS', '220 Volts')
,('2-73432', 'R20116-1614-06', 'PB Controls')
,('2-78125', 'R20116-1614-06', 'PB Controls')
,('2-74803', 'R20116-1614-06', 'PB Controls Dual W/Selector and Beeper')
,('2-78125', 'R20116-1614-06', '50 Hertz')
,('2-74803', 'R20116-1614-06', '50 Hertz')
,('2-73432', 'R20116-1614-06', '60 Hertz')
,('2-73432', 'R20116-1614-06', 'Right Side Front and Back Location')
,('2-74803', 'R20116-1614-06', 'Right Side Front and Back Location')
,('2-78125', 'R20116-1614-06', 'Right Side Front Location')
,('2-78125', 'R20116-1614-06', '1 x 1.50HP Motor')
,('2-73432', 'R20116-1614-06', '1 x 1.50HP Motor')
,('2-74803', 'R20116-1614-06', '1 x 1.50HP Motor')
,('2-74803', 'R20116-1614-06', 'Pigtail, Top Option')
,('2-74803', 'R20116-1614-06', '1 Phase')
,('2-78125', 'R20116-1614-06', '1 Phase')
,('2-73432', 'R20116-1614-06', '3 Phase')
,('2-74803', 'R20116-1614-06', '110 Volts')
,('2-78125', 'R20116-1614-06', '208 Volts')
,('2-73432', 'R20116-1614-06', '480 Volts')
,('2-76582', 'R20116-1614-09', 'PB Controls')
,('2-76582', 'R20116-1614-09', '60 Hertz')
,('2-76582', 'R20116-1614-09', 'Right Side Front and Back Location')
,('2-76582', 'R20116-1614-09', '2 x 1.50HP Motor')
,('2-76582', 'R20116-1614-09', '3 Phase')
,('2-76582', 'R20116-1614-09', '220 Volts')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', 'Keypad PB Controls')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', '60 Hertz')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', 'Right Side Front Location')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', '1 x 1.50HP Motor')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', '3 Phase')
,('2-59350', 'R20116-1614-12-STD-CNTRLS', '220 Volts')
,('2-77592', 'R20158-2214-06', 'PB Controls Dual W/Selector and Beeper')
,('2-77592', 'R20158-2214-06', '60 Hertz')
,('2-77592', 'R20158-2214-06', 'Right Side Front and Back Location')
,('2-77592', 'R20158-2214-06', '2 x 1.00HP Motor')
,('2-77592', 'R20158-2214-06', '3 Phase')
,('2-77592', 'R20158-2214-06', '208 Volts')
,('2-48924', 'R20179-2514-12', 'Keypad PB Controls')
,('2-48924', 'R20179-2514-12', '60 Hertz')
,('2-48924', 'R20179-2514-12', 'Right Side Front and Back Location')
,('2-48924', 'R20179-2514-12', '1 x 1.50HP Motor')
,('2-48924', 'R20179-2514-12', '3 Phase')
,('2-48924', 'R20179-2514-12', '208 Volts')
,('2-70697', 'R20228-3214-06', 'PB Controls')
,('2-70697', 'R20228-3214-06', '60 Hertz')
,('2-70697', 'R20228-3214-06', 'Right Side Front Location')
,('2-70697', 'R20228-3214-06', '2 x 1.00HP Motor')
,('2-70697', 'R20228-3214-06', '3 Phase')
,('2-70697', 'R20228-3214-06', '208 Volts')
,('2-76637', 'R24125-1220-06-DC 2-76637', 'PB Controls Dual W/Selector and Beeper')
,('2-76637', 'R24125-1220-06-DC 2-76637', '60 Hertz')
,('2-76637', 'R24125-1220-06-DC 2-76637', 'Top Right Side Front and Back Location')
,('2-76637', 'R24125-1220-06-DC 2-76637', '3 Phase')
,('2-76637', 'R24125-1220-06-DC 2-76637', '208 Volts')
,('2-76965', 'R39150-MS-06-DC 2-76965', 'PB Controls')
,('2-76965', 'R39150-MS-06-DC 2-76965', '60 Hertz')
,('2-76965', 'R39150-MS-06-DC 2-76965', 'Left Side Front and Back Location')
,('2-76965', 'R39150-MS-06-DC 2-76965', '2 x 1.00HP Motor')
,('2-76965', 'R39150-MS-06-DC 2-76965', '3 Phase')
,('2-76965', 'R39150-MS-06-DC 2-76965', '208 Volts')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', 'Keypad PB Controls')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', '60 Hertz')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', 'Right Side Front Location')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', '1 x 1.00HP Motor')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', '3 Phase')
,('2-76909', 'SMALL WIRE CRSL R24159-1422-52', '208 Volts')
,('2-54416', 'T39148-0740-15', 'Keypad PB Controls')
,('2-54416', 'T39148-0740-15', '60 Hertz')
,('2-54416', 'T39148-0740-15', 'Right Side Front Location')
,('2-54416', 'T39148-0740-15', '2 x 1.50HP Motor')
,('2-54416', 'T39148-0740-15', '3 Phase')
,('2-54416', 'T39148-0740-15', '208 Volts')
,('2-56095', 'T39188-0940-15-SV', 'Keypad PB Controls')
,('2-56095', 'T39188-0940-15-SV', '60 Hertz')
,('2-56095', 'T39188-0940-15-SV', 'Right Side Front Location')
,('2-56095', 'T39188-0940-15-SV', '2 x 1.50HP Motor')
,('2-56095', 'T39188-0940-15-SV', '3 Phase')
,('2-56095', 'T39188-0940-15-SV', '208 Volts')
,('2-53564', 'T45156-0744-15', 'Keypad PB Controls')
,('2-53564', 'T45156-0744-15', '60 Hertz')
,('2-53564', 'T45156-0744-15', 'Right Side Front Location')
,('2-53564', 'T45156-0744-15', '2 x 1.50HP Motor')
,('2-53564', 'T45156-0744-15', '3 Phase')
,('2-53564', 'T45156-0744-15', '208 Volts')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', 'Keypad PB Controls')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', '60 Hertz')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', 'Right Side Front Location')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', '2 x 1.50HP Motor')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', '3 Phase')
,('2-65573', 'T45200-0944-15 SV WITH FOLDING GATE', '480 Volts')
,('2-76617', 'W39191-1134-06 2-76617', 'Keypad PB Controls')
,('2-76617', 'W39191-1134-06 2-76617', '60 Hertz')
,('2-76617', 'W39191-1134-06 2-76617', 'Right Side Front Location')
,('2-76617', 'W39191-1134-06 2-76617', '2 x 1.00HP Motor')
,('2-76617', 'W39191-1134-06 2-76617', '3 Phase')
,('2-76617', 'W39191-1134-06 2-76617', '208 Volts')
,('2-70274', 'W39250-1630-16.5', 'Keypad PB Controls')
,('2-70274', 'W39250-1630-16.5', '50 Hertz')
,('2-70274', 'W39250-1630-16.5', 'Right Side Front Location')
,('2-70274', 'W39250-1630-16.5', '2 x 1.50HP Motor')
,('2-70274', 'W39250-1630-16.5', '3 Phase')
,('2-70274', 'W39250-1630-16.5', '208 Volts')
,('2-57285', 'W45243-1240-W-100', 'Keypad PB Controls')
,('2-57285', 'W45243-1240-W-100', '60 Hertz')
,('2-57285', 'W45243-1240-W-100', 'Right Side Front Location')
,('2-57285', 'W45243-1240-W-100', '2 x 1.50HP Motor')
,('2-57285', 'W45243-1240-W-100', '3 Phase')
,('2-57285', 'W45243-1240-W-100', '208 Volts')
GO
-- Query Parms
DECLARE
@Desc nvarchar(40) = NULL
,@P1 nvarchar(40) = NULL
,@P2 nvarchar(40) = NULL
,@P3 nvarchar(40) = NULL
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL
-- Encase parm values with wildcards, and replace spaces in parm values with wildcards
SELECT
@Desc = '%' + REPLACE(@Desc, ' ', '%') + '%'
,@P1 = '%' + REPLACE(@P1, ' ', '%') + '%'
,@P2 = '%' + REPLACE(@P2, ' ', '%') + '%'
,@P3 = '%' + REPLACE(@P3, ' ', '%') + '%'
,@P4 = '%' + REPLACE(@P4, ' ', '%') + '%'
,@P5 = '%' + REPLACE(@P5, ' ', '%') + '%';
-- Create temp table to hold the @P1 - @P5 parms
CREATE TABLE #Parms_List(parms nvarchar(40));
-- Insert @P parms into temp table for use later in INNER JOIN
WITH p (parms)
AS
(
SELECT @P1
UNION ALL SELECT @P2
UNION ALL SELECT @P3
UNION ALL SELECT @P4
UNION ALL SELECT @P5
)
INSERT INTO #Parms_List
SELECT parms FROM p WHERE parms IS NOT NULL
-- Insert all distinct cat_desc if all @P parms are null
IF @P1 IS NULL AND @P2 IS NULL AND @P3 IS NULL AND @P4 IS NULL AND @P5 IS NULL
BEGIN
INSERT INTO #Parms_List
SELECT DISTINCT c.cat_desc
FROM #Item_Category_List AS c
END
-- Create temp table to hold matching item numbers for @Desc search
CREATE TABLE #Item_Desc_Match_List(item nvarchar(30));
-- Search #Item_Category_List for matching items based on description
-- and insert into #Item_Desc_Match_List for use later in INNER JOIN
IF @Desc IS NOT NULL
BEGIN
-- Insert only matching items from #Item_Category_List
INSERT INTO #Item_Desc_Match_List
SELECT DISTINCT t.item
FROM #Item_Category_List AS t
WHERE t.item_desc LIKE @Desc
END
ELSE
BEGIN
-- Insert all items from #Item_Category_List
INSERT INTO #Item_Desc_Match_List
SELECT DISTINCT t.item
FROM #Item_Category_List AS t
END
-- Final Query for matching items
SELECT DISTINCT t.item
FROM #Item_Category_List AS t
INNER JOIN #Item_Desc_Match_List AS i
ON i.item = t.item
INNER JOIN #Parms_List AS p
ON t.cat_desc LIKE p.parms
ORDER BY t.item
DROP TABLE #Item_Category_List
DROP TABLE #Parms_List
DROP TABLE #Item_Desc_Match_List
为@P1
和@P5
。
对于项目描述查询,我创建了一个临时表@Desc
,并且我将临时日期表插入了描述匹配的#Item_Desc_Match_List
项列表,然后我在最后的查询中执行了DISTINCT
这个INNER JOIN
表。{/ p>
对于类别搜索,我的第一次尝试只是尝试像这样的where子句,#Item_Desc_Match_List
等...但是因为5个WHERE cat_desc LIKE @P1 OR cat_desc LIKE @P2
parms中的任何一个都可以为null,没用。所以我的第二种方法是将所有@P
parms放入临时表中,然后在@P
列的最终查询中对{temp}数据表执行INNER JOIN
。这很有用。
使用以下查询参数运行以上代码:
cat_desc
您将获得以下结果:
@Desc nvarchar(40) = '1614'
,@P1 nvarchar(40) = NULL
,@P2 nvarchar(40) = NULL
,@P3 nvarchar(40) = NULL
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL
到目前为止,这是正确的,因为所有这些项目的描述中都有 1614 。现在将item
------------------------------
2-59350
2-73432
2-74803
2-76582
2-78125
更改为@P1
,结果为:
'60 hertz'
这也是正确的,因为这三个项目的描述中 1614 ,并且它们都链接了 60赫兹类别。现在将item
------------------------------
2-59350
2-73432
2-76582
更改为@P2
,结果保持不变。这是问题的开始,因为只有项目编号2-76582和2-59350链接了 220伏类别。
将'220 Volt'
更改为@P3
,结果应该减少到只有一个2-59350,因为该项目#是唯一一个描述类似的项目{{1链接的类别与'1 x 1.50HP'
,@Desc
和@P1
匹配。
我已经在这个报告上旋转了几天,我不确定如何在我定义更多@P2
parms时缩小我的结果,而不是增加我的结果就像现在一样。
答案 0 :(得分:0)
问题在于,您匹配的结果是 ANY 行与cat_desc
匹配,而不是所有行。
对于您最简单的示例,让我们假设你的第二个案例没有DISTINCT
:
DECLARE @Desc nvarchar(40) = '1614'
,@P1 nvarchar(40) = '60 hertz'
,@P2 nvarchar(40) = '220 Volt'
,@P3 nvarchar(40) = NULL
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL;
WITH p (param) AS
(
SELECT param
FROM (VALUES (@p1), (@p2), (@p3), (@p4), (@p5)) p (param)
WHERE p.param IS NOT NULL
)
SELECT *
FROM #Item_Category_List AS t
INNER JOIN p
ON t.cat_desc LIKE '%' + p.param + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%';
您实际上正在返回所有行:
item item_desc cat_desc param
--------------------------------------------------------
2-73432 R20116-1614-06 60 Hertz 60 hertz
2-76582 R20116-1614-09 60 Hertz 60 hertz
2-76582 R20116-1614-09 220 Volts 220 Volt
2-59350 R20116-1614-12-STD-CNTRLS 60 Hertz 60 hertz
2-59350 R20116-1614-12-STD-CNTRLS 220 Volts 220 Volt
您真正需要的是按item
分组并计算匹配的行数:
SELECT t.item, Matches = COUNT(*)
FROM #Item_Category_List AS t
INNER JOIN p
ON t.cat_desc LIKE '%' + p.param + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%'
GROUP BY t.item;
给出了:
item Matches
-------------
2-59350 2
2-73432 1
2-76582 2
然后您可以将结果限制为与参数数量匹配的项目(即匹配所提供的所有参数而不是任何参数):
DECLARE @Desc nvarchar(40) = '1614'
,@P1 nvarchar(40) = '60 hertz'
,@P2 nvarchar(40) = '220 Volt'
,@P3 nvarchar(40) = NULL
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL;
WITH p (param) AS
(
SELECT param
FROM (VALUES (@p1), (@p2), (@p3), (@p4), (@p5)) p (param)
WHERE p.param IS NOT NULL
)
SELECT t.item
FROM #Item_Category_List AS t
INNER JOIN p
ON t.cat_desc LIKE '%' + p.param + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%'
GROUP BY t.item
HAVING COUNT(p.Param) = (SELECT COUNT(*) FROM P);
这给出了期望的结果:
item
------------
2-59350
2-76582
最后,对于你的上一个案例,你会得到一条记录(2-59350):
DECLARE @Desc nvarchar(40) = '1614'
,@P1 nvarchar(40) = '60 hertz'
,@P2 nvarchar(40) = '220 Volt'
,@P3 nvarchar(40) = '1 x 1.50HP'
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL;
WITH p (param) AS
(
SELECT param
FROM (VALUES (@p1), (@p2), (@p3), (@p4), (@p5)) p (param)
WHERE p.param IS NOT NULL
)
SELECT t.item
FROM #Item_Category_List AS t
INNER JOIN p
ON t.cat_desc LIKE '%' + p.param + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%'
GROUP BY t.item
HAVING COUNT(p.Param) = (SELECT COUNT(*) FROM P);
这当然不考虑没有提供参数,也没有说明,所以这里我将内连接更改为左连接,并在having和where子句中添加额外的逻辑以允许不提供参数:
DECLARE @Desc nvarchar(40) = NULL
,@P1 nvarchar(40) = NULL
,@P2 nvarchar(40) = NULL
,@P3 nvarchar(40) = NULL
,@P4 nvarchar(40) = NULL
,@P5 nvarchar(40) = NULL;
WITH p (param) AS
(
SELECT param
FROM (VALUES (@p1), (@p2), (@p3), (@p4), (@p5)) p (param)
WHERE p.param IS NOT NULL
)
SELECT t.item
FROM #Item_Category_List AS t
LEFT JOIN p
ON t.cat_desc LIKE '%' + p.param + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%'
OR @Desc IS NULL
GROUP BY t.item
HAVING COUNT(p.Param) = (SELECT COUNT(*) FROM P)
OR (SELECT COUNT(*) FROM P) = 0;
这不太可能表现良好,但由于您的所有比较都像操作一样,我不认为您可以避免全表扫描。
顺便说一下,我会考虑使用表值参数,而不是你的6个参数:
CREATE TYPE dbo.ListOfString AS TABLE (Value NVARCHAR(MAX));
我倾向于为这样的事情创建泛型类型,因此它们更可重用,但这是个人偏好,如果你不介意有大量的类型,并担心表格中的严格数据,那么感觉免费使类型更具体。
然后您的程序将是:
CREATE PROCEDURE dbo.SearchItemCategoryList @Desc NVARCHAR(40), @Params dbo.ListOfString READONLY
AS
BEGIN
SELECT t.item
FROM dbo.Item_Category_List AS t
LEFT JOIN @Params AS p
ON t.cat_desc LIKE '%' + p.Value + '%'
WHERE t.item_desc LIKE '%' + @Desc + '%'
OR @Desc IS NULL
GROUP BY t.item
HAVING COUNT(p.Value) = (SELECT COUNT(*) FROM @Params)
OR (SELECT COUNT(*) FROM @Params) = 0;
END
您可以使用以下内容调用该过程:
-- GET ALL
DECLARE @P dbo.ListOfString;
EXECUTE dbo.SearchItemCategoryList NULL, @p;
GO
-- GET MATCHING JUST DESCRIPTION
DECLARE @P dbo.ListOfString;
EXECUTE dbo.SearchItemCategoryList '1614', @p;
GO
-- GET USING ONE PARAMETER
DECLARE @P dbo.ListOfString;
INSERT @p (Value) VALUES ('60 hertz');
EXECUTE dbo.SearchItemCategoryList '1614', @p;
GO
-- GET USING THREE PARAMETERS
DECLARE @P dbo.ListOfString;
INSERT @p (Value) VALUES ('60 hertz'), ('220 Volt'), ('1 x 1.50HP');
EXECUTE dbo.SearchItemCategoryList '1614', @p;
<强> Example on SQL Fiddle 强>