在SQL Server

时间:2017-07-30 07:38:18

标签: sql-server subquery common-table-expression

我有两张桌子:

产品

ProductId | Name  | Description 
----------+-------+-------------------------------------
1         | shirt | this is description for shirt
2         | pent  | this is description for pent

ProductOverride

ProductOverrideId | ColumnId  | Value                  | ProductId 
------------------+-----------+------------------------+-----------
1                 | 1         | overridden name        | 1
2                 | 2         | overridden description | 1

其中ColumnId来自column_id sys.columns

我想选择具有以下要求的所有产品:

如果在ProductOverride表中覆盖了产品名称或产品描述,请获取名称/描述的重写值,否则从产品表中获取名称/描述值。

示例输出:

ProductId | Name            | Description 
----------+-----------------+---------------------------
1         | overridden name | overridden description
2         | pent            | this is description for pent

我有以下查询返回确切的结果。

DECLARE @productNameColumnId INT = 1;
DECLARE @productDescriptionColumnId INT = 2;

WITH OverriddenProductNameCTE ([Value], [ProductId]) AS 
(
   SELECT 
       temp.[Value], temp.ProductId 
   FROM 
       ProductOverride temp 
   WHERE 
       temp.ColumnId = @productNameColumnId 
), OverriddenProductDescriptionCTE ([Value], [ProductId]) AS 
(
    SELECT 
        temp.[Value], temp.ProductId 
    FROM 
        ProductOverride temp 
    WHERE 
        temp.ColumnId = @productDescriptionColumnId
)
SELECT 
    p.ProductId,
    CASE 
       WHEN EXISTS(SELECT [Value] 
                   FROM OverriddenProductNameCTE opnc 
                   WHERE opnc.ProductId = p.ProductId) 
          THEN (SELECT [Value] 
                FROM OverriddenProductNameCTE opnc 
                WHERE opnc.ProductId = p.ProductId)
          ELSE p.[Name]
    END AS [Name],
    CASE 
        WHEN EXISTS(SELECT [Value] 
                    FROM OverriddenProductDescriptionCTE opdc 
                    WHERE opdc.ProductId = p.ProductId) 
           THEN (SELECT [Value] 
                 FROM OverriddenProductDescriptionCTE opdc 
                 WHERE opdc.ProductId = p.ProductId)
           ELSE p.[Description]
    END AS [Description]
FROM 
    product p

但是在CASE语句中,我有以下重复代码:

SELECT [Value] 
FROM OverriddenProductNameCTE opnc  
WHERE opnc.ProductId = p.ProductId

表示如果CASE语句的第一个条件为真,DBMS将在THEN部分再次执行相同的查询。

我希望在简化查询和处理方面改进此查询。

此外,如果在这种情况下使用CTE有任何优势吗?

1 个答案:

答案 0 :(得分:0)

如果它只有2列,我认为你能做的最简单的事情是连接两次加入:

SELECT p.ProductId
      ,COALESCE(poN.Value, p.Name) As Name 
      ,COALESCE(poD.Value, p.Description) As Description 
FROM Product p 
LEFT JOIN ProductOverride poN ON p.ProductId = poN.ProductId AND poN.ColumnId = 1 
LEFT JOIN ProductOverride poD ON p.ProductId = poD.ProductId AND poD.ColumnId = 2 

如果它是更多列,我会建议转动ProductOverride表并离开连接 - 就像这样(一个完整的例子):

创建并填充样本表(在将来的问题中保存此步骤)

CREATE TABLE Product
(
    ProductId int,
    Name varchar(100),
    Description  varchar(100),
    price int null
);

INSERT INTO Product VALUES
(1, 'shirt', 'Description for shirts', 1),
(2, 'Pants', 'Description for pants', 4),
(3, 'Socks', 'Description for socks', 5)

CREATE TABLE ProductOverride
(
    ProductOverrideId int, 
    ColumnId int, 
    Value varchar(100), 
    ProductId int
);

INSERT INTO ProductOverride VALUES
(1,1,'product 1 name',1),
(2,2,'product 1 desc',1),
(3,3,'7',1),
(4,1,'pants name',2),
--Note: no pants description in the override tabl
(6,3,'8',2);
-- Note: no socks at all in override table

查询:

SELECT p.ProductId 
      ,COALESCE(override.[1], p.Name) As Name 
      ,COALESCE(override.[2], p.Description) As Description 
      ,COALESCE(CAST(override.[3] as int), p.Price) As Price
FROM Product p 
LEFT JOIN
(
    SELECT *
    FROM 
    (
        SELECT ProductId, Value, ColumnId -- Columns To use for pivot
        FROM ProductOverride                                
    ) ColumnsToPivot
    PIVOT (
       max (Value)
       for ColumnId in ([1], [2], [3]) -- Values in ColumnId column to make the column names
    ) as pivotedData
) as override ON p.ProductId = override.ProductId

结果:

ProductId   Name    Description Price
1   product 1 name  product 1 desc  7
2   pants name  Description for pants   8
3   Socks   Description for socks   5

You can see a live demo on rextester.