Combine several rows with null values into one

爱⌒轻易说出口 提交于 2019-12-04 05:51:17

问题


I have a little problem with my select statement. I need to select the latest record for each type of phones from my table, so I try this code:

CREATE TABLE contacts(
tel_number VARCHAR2(14),
tel_type NUMBER,
row_id_con NUMBER,
record_id NUMBER
);

CREATE TABLE orders(
order_id VARCHAR2(9),
row_id_ord NUMBER
);

INSERT INTO contacts VALUES('444-444-444', 1, 1, 1);
INSERT INTO contacts VALUES('22-22-22', 2, 1, 2);
INSERT INTO contacts VALUES('555-555-555', 1, 1, 3);

INSERT INTO orders VALUES('111111111', 1);

SELECT ord.order_id, 
       DECODE(con.tel_type, 1, con.tel_number) AS number1,
       DECODE(con.tel_type, 2, con.tel_number) AS number2
FROM  (SELECT MAX(c.record_id) as max_row_id
       FROM contacts c, orders o
       WHERE c.row_id_con = o.row_id_ord
       and o.order_id = '111111111'
       GROUP BY c.tel_type) c, contacts con, orders ord
WHERE  con.row_id_con = ord.row_id_ord 
       and con.record_id = c.max_row_id
GROUP BY ord.order_id, con.tel_type, con.tel_number;

The output now is like that:

order_id   number1      number2
111111111  null         22-22-22
111111111  555-555-555  null

But I need something like that:

order_id   number1      number2
111111111  555-555-555  22-22-22

How can I do that?


回答1:


On more solution:

SELECT o.order_id,
       max( case c.tel_type when 1 then tel_number end ) 
           KEEP ( DENSE_RANK LAST ORDER BY row_id_con NULLS FIRST ) as number1,
       max( case c.tel_type when 2 then tel_number end ) 
           KEEP ( DENSE_RANK LAST ORDER BY row_id_con NULLS FIRST ) as number2
FROM orders o
LEFT JOIN contacts c ON c.row_id_con = o.row_id_ord
GROUP BY o.order_id
;



回答2:


Wrap it with rownum < 2 and add order by to get largest record_id:

select * from (
SELECT ord.order_id, 
       DECODE(con.tel_type, 1, con.tel_number) AS number1,
       DECODE(con.tel_type, 2, con.tel_number) AS number2
FROM  (SELECT MAX(c.record_id) as max_row_id
       FROM contacts c, orders o
       WHERE c.row_id_con = o.row_id_ord
       and o.order_id = '111111111'
       GROUP BY c.tel_type) c, contacts con, orders ord
WHERE  con.row_id_con = ord.row_id_ord 
       and con.record_id = c.max_row_id
GROUP BY ord.order_id, con.tel_type, con.tel_number
order by c.record_id desc
)
where rownum < 2;

You can change the order by clause to get other order than c.record_id desc




回答3:


You want to use row_number(). Something like this:

SELECT o.order_id,
       MAX(CASE WHEN tel_type = 1 AND seqnum = 1 THEN tel_number END) as number1,
       MAX(CASE WHEN tel_type = 2 AND seqnum = 1 THEN tel_number END) as number2
FROM  (SELECT o.order_id, c.*,
              ROW_NUMBER() OVER (PARTITION BY o.order_id, c.tel_type
                                 ORDER BY record_id DESC
                                ) as seqnum
       FROM contacts c JOIN
            orders o
            ON c.row_id_con = o.row_id_ord AND
               o.order_id = '111111111'
      ) o
GROUP BY order_id;

Notes:

  • Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
  • CASE is preferable to DECODE() because it is ANSI standard SQL, so it is part of the standard language.
  • You can use window functions to greatly simplify the query and improve performance.
  • You can remove the condition on order_id in the subquery to get rows for all orders.
  • You want the GROUP BY to only contain the columns that define each row in your desired result set.


来源:https://stackoverflow.com/questions/45400335/combine-several-rows-with-null-values-into-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!