【问题标题】:How to select distinct value from multiple tables given a column filter?给定列过滤器,如何从多个表中选择不同的值?
【发布时间】: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 不能同时是 ProductCodeProductName 那么为什么两个分支填充一个表变量呢?为什么不只是两个分支直接返回搜索结果?
  • 您正在根据您的查询获得正确的值。不同的产品代码。如果您只想要前 4 位数字,则必须执行 DISTINCT LEFT(ProductCode, 4) (或类似的操作。但我不认为这是一个好主意
  • 您应该选择 [Name]、min([ProductId]) 并按名称分组,而不是不同的,分别是方案 2 中的代码
  • 您将难以使用生成因数据类型而异的结果集的存储过程。推测 ProductID 是 Product 表的主键(或至少是唯一的),因此 DISTINCT 没有逻辑效果。每次执行两次也没有多大意义。不要依赖数据库引擎来忽略逻辑错误以优化您的代码。如果代码和名称都不是唯一的,也许您会寻找“每组第一个”?

标签: sql sql-server distinct


【解决方案1】:

检查以下代码:

使用MIN函数

DECLARE
@filter nvarchar(max) = 'ProductCode',
@search nvarchar(max)='P000',
@rows int = 10

BEGIN
DECLARE @return TABLE([id] INT, [value] NVARCHAR(50));

IF (@filter = 'ProductCode')
BEGIN
    INSERT INTO @return([value], [id])
    SELECT TOP (@rows) [Code] AS ProductCode,  MIN( Id)
    FROM @Products
    WHERE [Code] LIKE CONCAT(@search, '%')
     GROUP BY [Code]
    ORDER BY [Code];
END
IF (@filter = 'ProductName')
BEGIN
    INSERT INTO @return([value], [id])
    SELECT TOP (@rows)[Name] AS ProductName, MIN( Id)
    FROM @Products
    WHERE [Name] LIKE CONCAT(@search, '%')
    GROUP BY [Name]
    ORDER BY [Name];
END

SELECT TOP (@rows) [id], [value] 
FROM @return
ORDER BY [id],[value]
END

【讨论】:

  • 尝试这个解决方案
  • 这行得通。只需将@Products 更改为 [dbo].[Products]
猜你喜欢
  • 2021-11-25
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多