0

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 |

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 |

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.

Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73
Clint_A
  • 518
  • 2
  • 11
  • 35
  • Is there a problem joining both parts using com_id field? Is com_id unique (PK) for each table? If com_id is unique (I have a feeling it is) then you could just use simple join: select a.com_id, a.message_date, a.message_text, a.message_by, b.recipient_name, b.phone_number from ([Your first SELECT]) a join ([Your second SELECT]) b on a.com_id = b.com_id – Edgars T. Dec 14 '17 at 08:18
  • Can one communication include several SMS? And all the SMS in a communication are sent from `c.message_from`? That seems so strange. – Thorsten Kettner Dec 14 '17 at 08:41
  • Yes, one communication can include several SMS's. Basically, one user can send one message to several recipients depending on the selection. So the sms text is the `message`, the user (sender of the message) is the `message_by` and the receivers of the sms are the recipients. – Clint_A Dec 14 '17 at 09:03
  • The `com_id`'s are similar. One is a foreign key to the other – Clint_A Dec 14 '17 at 09:04

3 Answers3

2

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

Paul Maxwell
  • 33,002
  • 3
  • 32
  • 51
  • Yes, the `com_id`'s are equal. One is a foreign key to the other. This query looks promising however I keep running into an error at this point - `s1 on u.com_id = s1.com_id`. Says `column u.com_id does not exist` – Clint_A Dec 14 '17 at 09:24
  • `com_id` exists in both tables and are equal – Clint_A Dec 14 '17 at 09:25
  • I missed adding an alias in the first dubquery, I just fixed that – Paul Maxwell Dec 14 '17 at 10:52
0

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
Tomm
  • 1,021
  • 2
  • 14
  • 34
0

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;
Thorsten Kettner
  • 89,309
  • 7
  • 49
  • 73
  • From the `communications` table there's an option where a user can either send a communication as an SMS or an email. If the user sends an email then `send_as_sms = FALSE`. Also, the first query is only executed when `send_as_sms = TRUE` so that there'll always a result but I want only the latest. – Clint_A Dec 14 '17 at 09:30
  • I use `MAX(cs.com_id)` to get only the last result because it's what both tables have in common. Each time a new communication is sent, a new `com_id` is assigned to that entry. – Clint_A Dec 14 '17 at 09:35
  • Look at your first query: `WHERE send_as_sms = TRUE AND com_id = (SELECT MAX(com_id) FROM app.communications)`. Now imagine the last communication was an email communication. Then `send_as_sms` is `FALSE` and the query returns no rows. – Thorsten Kettner Dec 14 '17 at 09:37
  • As for the design, I'm only extending the application. But from what I gather, the `comminications` table only store the basic data of the given communication like sender id, message id etc. Then depending on the communication type (SMS or email) the particulars are entered into the respective table, `communication_sms` or `communication_email`. The particulars are things like names, phone, message etc – Clint_A Dec 14 '17 at 09:41
  • If the last communication is an email, the query is not executed at all. The emails have their own queries. – Clint_A Dec 14 '17 at 09:44
  • The flag `send_as_sms` seems redundant and thus dangerous. Or is `send_as_sms = TRUE` without `communication_sms` possible and desired? Is `send_as_sms = FALSE` with `communication_sms` records? – Thorsten Kettner Dec 14 '17 at 09:46
  • Are you saying that you check whether the last communication was an email, before executing the query? – Thorsten Kettner Dec 14 '17 at 09:47
  • I agree, the `send_as_sms` and `send_as_email` flags could have been avoided. But that's what I have to work with without rewriting too many things. And yes, the communication type is checked before executing the query. It's actually checked using a radio button so there's no overhead on the requests – Clint_A Dec 14 '17 at 09:55
  • A radio button? So there is some person using a program and that persons knows by some means whether the last entry in the communication table is of type email or SMS and must click that radio button? That sounds absolutely weird. I can imagine a user asking to see the last email conversation or the last SMS communication, but it's hard to imagine a user finding out what type the last communication was and telling the program about their findings. – Thorsten Kettner Dec 14 '17 at 11:45
  • It's actually simpler than you might imagine. The radio button is on the original form for sending the messages. You click the radio button to denote what type of message you're sending and brings up the appropriate text fields. So on submit, a simple if statement will suffice. And the queries are not meant for the end users - the data is meant for further processing via an API – Clint_A Dec 14 '17 at 11:58