使用自联接将2行合并为1

时间:2016-08-24 17:55:06

标签: sql sql-server join

遵循简化表格

CustNr OrderNr Date    Price Curry
1      555     030316  2,4   EUR
1      666     030316  2,5   EUR
1      777     030316  2,3   EUR
1      777     030316  1,9   USD
1      888     030316  2,3   EUR
1      888     030316  2,4   EUR

期望的输出:

CustNr OrderNr Date    Price Curry   CustNr OrderNr Date    Price Curry
1      555     030316  2,4   EUR
1      666     030316  2,5   EUR
1      777     030316  2.3   EUR     1      777     030316   1,9   USD
1      888     030316  2,3   EUR     1      888     030316   2,4   EUR

我试过跟随自我加入:

SELECT * FROM TEST T1 INNER JOIN TEST T2 ON T1.OrderNr = T2.OrderNr

但是后来我得到了重复的记录,GROUP BY仅在按OrderNr分组时才有效,但我也需要其他列。

5 个答案:

答案 0 :(得分:4)

需要以某种方式对具有相同OrderNr的行进行编号。

with tn as (
    select *, rn=row_number() over(partition by OrderNr order by Price)
    from table
)
select t1.*, t2.*
from tn t1
left join tn t2 on t2.OrderNr = t1.OrderNr and t2.rn=2
where t1.rn=1

答案 1 :(得分:3)

我觉得你的问题不是100%清楚。但根据您当前的描述,此查询应该有效:

with cte as (
  select CustNr, OrderNr, Date, Price, Curry,
         row_number() over (partition by OrderNr order by OrderNr) as rn
    from test
)
select t1.CustNr, t1.OrderNr, t1.Date, t1.Price, t1.Curry,
       t2.CustNr, t2.OrderNr, t2.Date, t2.Price, t2.Curry
  from cte t1
  left join cte t2
    on t2.OrderNr = t1.OrderNr
   and t2.rn = 2
 where t1.rn = 1

通过上述查询,左侧与右侧出现的行完全是任意的。如果要定义哪一行去哪里,可以通过调整order by窗口函数中的row_number子句来实现。

答案 2 :(得分:1)

您应该使用左连接而不是内连接并按Curry过滤

SELECT * FROM TEST T1 LEFT JOIN TEST T2 ON (T1.OrderNr = T2.OrderNr
AND  T1.Curry <> T2.Curry )

答案 3 :(得分:0)

您需要一个代表唯一订单号的顶级查询:

select 
t.OrderNr,
t1.*,
t2.*
from (select distinct OrderNr from test) t
cross apply (select top 1 * from test t1 where t1.OrderNr = t.OrderNr order by Curry) t1
outer apply (select top 1 * from test t2 where t2.OrderNr = t.OrderNr and t2.Curry <> t1.Curry order by Curry) t2

我认为这回答了这个问题,但我认为它提出了更多关于所需输出设计的问题。

答案 4 :(得分:0)

你也可以尝试这个:

DECLARE @tab TABLE (
  CustNr int,
  OrderNr int,
  Date int,
  Price varchar(20),
  Curry char(3)
);
INSERT INTO @tab
  VALUES (1, 555, 030316, '2,4', 'EUR'),
  (1, 666, 030316, '2,5', 'EUR'),
  (1, 777, 030316, '2,3', 'EUR'),
  (1, 777, 030316, '1,9', 'USD'),
  (1, 888, 030316, '2,3', 'EUR'),
  (1, 888, 030316, '2,4', 'EUR');

SELECT
  T1.custNr,
  T1.OrderNr,
  T1.date,
  T1.price,
  T1.curry,
  T2.custNr,
  T2.OrderNr,
  T2.date,
  T2.price,
  T2.curry
FROM (SELECT
  T1.custNr,
  T1.OrderNr,
  T1.date,
  T1.price,
  T1.curry,
  ROW_NUMBER() OVER (PARTITION BY T1.custNr,
  T1.OrderNr ORDER BY T1.custNr,
  T1.OrderNr) AS [rank1]
FROM @tab T1) T1
LEFT JOIN (SELECT
  (custNr) AS custNr,
  OrderNr,
  (date) AS date,
  (price) AS price,
  (curry) AS curry,
  ROW_NUMBER() OVER (PARTITION BY custNr,
  OrderNr ORDER BY custNr,
  OrderNr) AS [rank]
FROM @tab T2) T2
  ON T1.OrderNr = T2.OrderNr
  AND T2.rank > 1
WHERE T1.rank1 <> 2
ORDER BY T1.OrderNr;