简体   繁体   中英

Merge two SELECT statements with different data types and number of columns into one output in PostgreSQL

I have two queries. The first -

SELECT
  communications.creation_date as message_date, 
  message as message_text, 
  employees.first_name || ' ' || coalesce(employees.middle_name,'') || ' ' || employees.last_name as message_by
FROM app.communications 
INNER JOIN app.employees ON communications.message_from = employees.emp_id 
WHERE send_as_sms = TRUE AND com_id = (SELECT MAX(com_id) FROM app.communications)

which basically outputs - | message_date | message_text | message_by | | message_date | message_text | message_by |

And the second query -

SELECT
  cs.com_id, 
  cs.first_name ||' ' || cs.last_name AS recipient_name, 
  cs.sim_number AS phone_number
FROM app.communication_sms cs
WHERE cs.com_id = (SELECT MAX(cs2.com_id) FROM app.communication_sms cs2)
ORDER BY first_name ASC

which outputs - | com_id | recipient_name | phone_number | | com_id | recipient_name | phone_number |

As you can tell from the queries, both tables have a "com_id" column. What I need is to make a single query that will merge the two queries above to get a single output, something like -

|message_date|message_text|message_by|recipient_name|phone_number|

How can I achieve that? I can't use UNION because of the different data types and different number of columns. I'll appreciate your help guys.

Not sure if the com_id will be equal or not, but in case they might not be then I suggest this:

select * -- list out the columns, I haven't bothered here
FROM (
      SELECT MAX(com_id) as com_id FROM app.communications 
      UNION
      SELECT MAX(cs2.com_id) FROM app.communication_sms cs2
      ) u
left join (
      SELECT
        com_id -- don't know which table this comes from
        communications.creation_date as message_date, 
        message as message_text, 
        employees.first_name || ' ' || coalesce(employees.middle_name,'') || ' ' || employees.last_name as message_by
      FROM app.communications 
      INNER JOIN app.employees ON communications.message_from = employees.emp_id 
      WHERE send_as_sms = TRUE AND com_id = (SELECT MAX(com_id) FROM app.communications)
     ) s1 on u.com_id = s1.com_id
left join (
SELECT
        cs.com_id, 
        cs.first_name ||' ' || cs.last_name AS recipient_name, 
        cs.sim_number AS phone_number
      FROM app.communication_sms cs
      WHERE cs.com_id = (SELECT MAX(cs2.com_id) FROM app.communication_sms cs2)
      ORDER BY first_name ASC
      ) s2 on u.com_id = s2.com_id

Note a small amount of repetition could be avoided by using CTEs

Is there a reason why you would need to union or join? In the context you are asking the question com_id should not matter.

Try something like this, ( this query is nothing special basically just merged the two together )

SELECT
  communications.creation_date as message_date, 
  message as message_text, 
  employees.first_name || ' ' || coalesce(employees.middle_name,'') || ' ' || employees.last_name as message_by
  cs.com_id, 
  cs.first_name ||' ' || cs.last_name AS recipient_name, 
  cs.sim_number AS phone_number
FROM app.communications, app.communication_sms cs
INNER JOIN app.employees ON communications.message_from = employees.emp_id 
WHERE send_as_sms = TRUE AND com_id = (SELECT MAX(com_id) FROM app.communications)
AND cs.com_id = (SELECT MAX(cs2.com_id) FROM app.communication_sms cs2)
ORDER BY first_name ASC

First query: You want the last communication identified by MAX(c.com_id) , but only in case it is an SMS ( c.send_as_sms = TRUE ). For this SMS you want the sender's name. This query results in one or zero rows depending on whether the last communication was an SMS.

Second query: You want the last SMSs for the last SMS communication this time identified by MAX(cs.com_id) . This looks redundant. Why do you have a send_as_sms in communications when you see from the existence of matching communication_sms records that this is an SMS? You may want to think over this design. Anyway, from this you want to get the recipient's name plus some phone number.

How to combine the two queries is not evident. Do you really want the latest SMSs with the recipients' names, but only add the sender's name in case this last SMS is also the last communication? This doesn't seem likely. I guess you rather want either

  1. the lastest communication in case its an SMS or
  2. the latest SMS communication

for both the sender and recipient. Or can you have non-SMS communications with SMSs attatched?

Here is a query for the last SMS communication:

SELECT
  c.creation_date AS message_date, 
  c.message AS message_text, 
  e.first_name || ' ' || coalesce(e.middle_name,'') || ' ' || e.last_name AS message_by,
  cs.com_id, 
  cs.first_name ||' ' || cs.last_name AS recipient_name, 
  cs.sim_number AS phone_number
FROM (SELECT * FROM app.communication_sms ORDER BY com_id DESC FETCH FIRST ROW ONLY) cs
JOIN app.communications c ON c.com_id = cs.com_id
JOIN app.employees e ON c.message_from = e.emp_id 
ORDER cs.first_name ASC;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM