如何与自己连接表并将其显示为单行

时间:2015-05-12 07:33:38

标签: sql sql-server

有一个名为PRODUCT_PRICE的表格:

CREATE TABLE [TEST].[PRODUCT_PRICE]
(
    [PRICE_ID] [bigint] NOT NULL,
    [PRODUCT_ID] [bigint] NOT NULL,
    [PRICE_DATE] [date] NOT NULL,
    [IS_SALE_PRICE] [bit] NOT NULL,
    [UNIT_PRICE] [decimal](18, 2) NOT NULL
)

它有以下记录:

PRICE_ID PRODUCT_ID PRICE_DATE  IS_SALE_PRICE UNIT_PRICE
-------- ---------- ----------  ------------- ----------
1        15         2015-05-12  False         0,05
2        15         2015-05-12  True          0,04
3        25         2015-05-12  False         1,45
4        35         2015-05-12  True          2,65

编辑:只能有两种价格 - 购买价格和促销价格。不能有3行或更多行具有相同的PRODUCT_IDPRICE_DATE

我想写一个SELECT语句,结果如下:

PRICE_ID PRODUCT_ID PRICE_DATE  IS_SALE_PRICE UNIT_PRICE PRICE_ID_2 IS_SALE_PRICE_2 UNIT_PRICE_2
-------- ---------- ----------  ------------- ---------- ---------- --------------- ------------
1        15         2015-05-12  False         0,05       2          True            0,04
3        25         2015-05-12  False         1,45       NULL       NULL            NULL
4        35         2015-05-12  True          2,65       NULL       NULL            NULL

我尝试了FULL OUTER JOIN,但它产生了4行而不是3行,这是正确的,但不是我想要的:

SELECT
    PR1.*,
    PR2.PRICE_ID AS PRICE_ID_2,
    PR2.IS_SALE_PRICE AS IS_SALE_PRICE_2,
    PR2.UNIT_PRICE AS UNIT_PRICE_2
FROM PRODUCT_PRICE AS PR1
FULL OUTER JOIN PRODUCT_PRICE AS PR2
    ON PR1.PRODUCT_ID = PR2.PRODUCT_ID
    AND PR1.PRICE_DATE = PR2.PRICE_DATE
    AND PR1.PRICE_ID <> PR2.PRICE_ID
    AND PR1.IS_SALE_PRICE <> PR2.IS_SALE_PRICE
WHERE
    PR1.PRICE_DATE = '20150512'
ORDER BY PR1.PRICE_ID

以上查询的结果:

| PRICE_ID | PRODUCT_ID | PRICE_DATE | IS_SALE_PRICE | UNIT_PRICE | PRICE_ID_2 | IS_SALE_PRICE_2 | UNIT_PRICE_2 |
|----------|------------|------------|---------------|------------|------------|-----------------|--------------|
|        1 |         15 | 2015-05-12 |         false |       0.05 |          2 |            true |         0.04 |
|        2 |         15 | 2015-05-12 |          true |       0.04 |          1 |           false |         0.05 |
|        3 |         25 | 2015-05-12 |         false |       1.45 |     (null) |          (null) |       (null) |
|        4 |         35 | 2015-05-12 |          true |       2.65 |     (null) |          (null) |       (null) |

基本上我想JOIN一个自己的表并删除重复项。

注意:PRICE_IDidentity字段(主键)。但自然键是PRODUCT_IDPRICE_DATE对。我想为每个唯一PRODUCT_IDPRICE_DATE添加一行。

SQL Fiddle

3 个答案:

答案 0 :(得分:3)

如果您确定每个PRODUCT_ID - PRICE_DATE组合最多只有2行,则可以使用条件聚合而不是JOIN

SQL Fiddle

SELECT
      PRICE_ID       = MAX(CASE WHEN RN = 1 THEN PRICE_ID END),
      PRODUCT_ID,
      PRICE_DATE,
      IS_SALE_PRICE  = MAX(CASE WHEN RN = 1 THEN CAST(IS_SALE_PRICE AS INT) END),
      UNIT_PRICE     = MAX(CASE WHEN RN = 1 THEN UNIT_PRICE END),
      PRICE_ID2      = MAX(CASE WHEN RN = 2 THEN PRICE_ID END),
      IS_SALE_PRICE2 = MAX(CASE WHEN RN = 2 THEN CAST(IS_SALE_PRICE AS INT) END),
      UNIT_PRICE2    = MAX(CASE WHEN RN = 2 THEN UNIT_PRICE END)
FROM (
    SELECT *,
        RN = ROW_NUMBER() OVER(PARTITION BY PRODUCT_ID, PRICE_DATE ORDER BY IS_SALE_PRICE)
    FROM PRODUCT_PRICE
)t
GROUP BY PRODUCT_ID, PRICE_DATE
ORDER BY PRODUCT_ID, PRICE_DATE

<强>结果

| PRICE_ID | PRODUCT_ID | PRICE_DATE | IS_SALE_PRICE | UNIT_PRICE | PRICE_ID2 | IS_SALE_PRICE2 | UNIT_PRICE2 |
|----------|------------|------------|---------------|------------|-----------|----------------|-------------|
|        1 |         15 | 2015-05-12 |             0 |       0.05 |         2 |              1 |        0.04 |
|        3 |         25 | 2015-05-12 |             0 |       1.45 |    (null) |         (null) |      (null) |
|        4 |         35 | 2015-05-12 |             1 |       2.65 |    (null) |         (null) |      (null) |

如果您坚持使用JOIN,则可以使用FULL JOIN

SQL Fiddle

SELECT
    PRICE_ID         = CASE WHEN PP.PRICE_ID IS NOT NULL THEN PP.PRICE_ID ELSE SP.PRICE_ID END,
    PRODUCT_ID       = CASE WHEN PP.PRICE_ID IS NOT NULL THEN PP.PRODUCT_ID ELSE SP.PRODUCT_ID END,
    PRICE_DATE       = CASE WHEN PP.PRICE_ID IS NOT NULL THEN PP.PRICE_DATE ELSE SP.PRICE_DATE END,
    IS_SALE_PRICE    = CASE WHEN PP.PRICE_ID IS NOT NULL THEN PP.IS_SALE_PRICE ELSE SP.IS_SALE_PRICE END,
    UNIT_PRICE       = CASE WHEN PP.PRICE_ID IS NOT NULL THEN PP.UNIT_PRICE ELSE SP.UNIT_PRICE END,
    PRICE_ID2        = CASE WHEN PP.PRICE_ID IS NOT NULL THEN SP.PRICE_ID END,
    IS_SALE_PRICE2   = CASE WHEN PP.PRICE_ID IS NOT NULL THEN SP.IS_SALE_PRICE END,
    UNIT_PRICE2      = CASE WHEN PP.PRICE_ID IS NOT NULL THEN SP.UNIT_PRICE END
FROM (
    SELECT *
    FROM PRODUCT_PRICE
    WHERE IS_SALE_PRICE = 0
)AS PP
FULL JOIN(
    SELECT *
    FROM PRODUCT_PRICE
    WHERE IS_SALE_PRICE = 1
)AS SP
    ON PP.PRODUCT_ID = SP.PRODUCT_ID
    AND PP.PRICE_DATE = SP.PRICE_DATE
ORDER BY PRODUCT_ID, PRICE_DATE

答案 1 :(得分:0)

您获得PRICE_ID=1 vs PRICE_ID =2PRICE_ID=2 vs PRICE_ID=1 所以你有一个重复的行。

ON CLAUSE中,join

时,您应该只强制PRICE_ID1 < PRICE_ID2

将此添加到ON CLAUSE:

AND PR1.PRICE_ID < PR2.PRICE_ID

并使用LEFT JOIN

随着这些变化,你将获得4行,你还需要避免第2行,因为它已经在行“内部”了。所以你只需要在where子句中过滤寄存器:

AND PR1.PRICE_ID in (select min(PRICE_ID) from PRODUCT_PRICE group by PRODUCT_ID)

答案 2 :(得分:0)

执行FULL OUTER JOIN

select ...
from PRODUCT_PRICE p1
  FULL OUTER JOIN PRODUCT_PRICE p2
    ON  p1.PRODUCT_ID = p2.PRODUCT_ID
    AND p1.PRICE_DATE = p2.PRICE_DATE
    AND p1.IS_SALE_PRICE = 'true
    AND p2.IS_SALE_PRICE = 'false'

编写选择列表列。并调整IS_SALE_PRICE比较。

替代解决方案,派生表FULL OUTER JOIN

select ...
from (select * from PRODUCT_PRICE
      where  IS_SALE_PRICE = 'true') as p1
  FULL OUTER JOIN
     (select * from PRODUCT_PRICE
      where  IS_SALE_PRICE = 'false') as p2
    ON  p1.PRODUCT_ID = p2.PRODUCT_ID
    AND p1.PRICE_DATE = p2.PRICE_DATE