【发布时间】:2021-03-16 12:20:42
【问题描述】:
我有这张桌子
产品
| Id | ProductName | ProductCode |
|---|---|---|
| 1 | Alexa | P0001 |
| 2 | Alexa | P0002 |
| 3 | Alexa 2 | P0003 |
| 4 | Aquarium | P0004 |
| 5 | Aquarium X | P0004 |
| 6 | Bathtub | P0005 |
CREATE PROCEDURE [dbo].[usp_GetFilter]
@filter nvarchar(max),
@search nvarchar(max),
@rows int = 10
AS
BEGIN
DECLARE @return TABLE([id] INT, [value] NVARCHAR(50));
IF (@filter = 'ProductCode')
BEGIN
INSERT INTO @return([value], [id])
SELECT DISTINCT TOP (@rows) [Code] AS ProductCode, ProductId Id
FROM [dbo].[Products]
WHERE [Code] LIKE CONCAT(@search, '%')
ORDER BY [Code];
END
IF (@filter = 'ProductName')
BEGIN
INSERT INTO @return([value], [id])
SELECT DISTINCT TOP (@rows)[Name] AS ProductName, ProductId Id
FROM [dbo].[Products]
WHERE [Name] LIKE CONCAT(@search, '%')
ORDER BY [Name];
END
SELECT DISTINCT TOP (@rows) [id], [value]
FROM @return
ORDER BY [value]
END
场景 1:
declare @filter nvarchar(max) = 'ProductName'
declare @search nvarchar(max) = 'A'
declare @rows int = 10
exec [dbo].[usp_GetFilter] filter, @search, @rows
预期结果:返回不同的 ProductName 和 Id
| Id | ProductName |
|---|---|
| 1 | Alexa |
| 3 | Alexa 2 |
| 4 | Aquarium |
| 5 | Aquarium X |
实际结果:
返回所有以“A”开头的产品名称,不同的不起作用
场景 2:
declare @filter nvarchar(max) = 'ProductCode'
declare @search nvarchar(max) = 'P000'
declare @rows int = 10
exec [dbo].[usp_GetFilter] filter, @search, @rows
预期结果:返回不同的产品代码以及 Id
| Id | ProductCode |
|---|---|
| 1 | P0001 |
| 2 | P0002 |
| 3 | P0003 |
| 4 | P0004 |
| 6 | P0005 |
实际结果:
返回所有以“P000”开头的产品代码,但不工作
【问题讨论】:
-
如果您的所有 ProductId 值都是不同的,如果您在 SELECT DISTINCT 中包含该列,您将在结果中从表中获取所有行
-
@Filter不能同时是ProductCode和ProductName那么为什么两个分支填充一个表变量呢?为什么不只是两个分支直接返回搜索结果? -
您正在根据您的查询获得正确的值。不同的产品代码。如果您只想要前 4 位数字,则必须执行 DISTINCT LEFT(ProductCode, 4) (或类似的操作。但我不认为这是一个好主意
-
您应该选择 [Name]、min([ProductId]) 并按名称分组,而不是不同的,分别是方案 2 中的代码
-
您将难以使用生成因数据类型而异的结果集的存储过程。推测 ProductID 是 Product 表的主键(或至少是唯一的),因此 DISTINCT 没有逻辑效果。每次执行两次也没有多大意义。不要依赖数据库引擎来忽略逻辑错误以优化您的代码。如果代码和名称都不是唯一的,也许您会寻找“每组第一个”?
标签: sql sql-server distinct