SQL get left join values from left table - sql

I am working on a complex sql query. Just for explaning purpose of my issue i have reduced to the below short query:
select a.column1 as field1,b.column2 as field 2,c.column3 as field3,COALESCE(SUM(d.paid_amt) OVER (PARTITION BY a.some_column),0) as amount_paid
from a Inner join b on b.column3=ac.olumn2
right join c on c.column4=b.column1
left join d on d.column2=a.column1 and d.column5 = a.column1
where ...//some conditions
SO i am quite sure whats happening here. I am more concerned on the last left join on d table. if the d table has no records which matches d.column5 = a.column1 then i am not getting any results.
But i am trying to write the query in such a way that if d table retuns any values with the where condition d.column5 = a.column1 then i want to use those values or else if there are no records in d table i just want to get the records from the result of previous joins and get the records that i need.
Here with the current query the problem is as expected, if the join doesnt match the where condition its eliminating all the records. I want to have the records no matter what if the where condition satisfies or not.
I am not quite sure how to do this in one single query. Any suggestions are appreciated.
Note: #scaisEdge and #Zaynul Answer works fine. but the problem is the amount caluclation if i move the condition in line on join and clause. The am ount calculation should also be on the same condition d.column5 = a.column1.So i am not really sure how to overcome this :(
Sample date below:
field1 | field2 | field3 | ampount_paid | some_column_to_match
--------------------------------------------------------------
name | value1 | other1 | 100 | 1
name1 | value2 | other2 | 100 | 1
name2 | value3 | other3 | 100 | 2
So i have just added the last columns to explain how i want the sum. I want sum the fields only if the some_column_to_match matches. So i am trying to get the output like:
field1 | field2 | field3 | amount_paid | some_column_to_match
--------------------------------------------------------------
name | value1 | other1 | 200 | 1
name1 | value2 | other2 | 200 | 1
name2 | value3 | other3 | 100 | 2
So basically the calculation should be the sum of all values in amount_paid where some_column_to_match value matches. So in the above example, the first two columns should return 200 as it as 100 in each individual field for the same value.

If you want a left join then you should not use columns of left joined table (d.column5 = a.column1) in where condition in this way the join became an inner join
In these case add the condition for the columns related to the left join table at the corresponding ON clase
select a.column1
,b.column2
,c.column3
,d.column4
from a Inner join b on b.column3=ac.olumn2
right join c on c.column4=b.column1
left join d on d.column2=a.column1 AND d.column5 = a.column1

Related

SQL Join On Columns of Different Length

I'm trying to join two tables together in SQL where the columns contain a different number of unique entries.
When I use a full join the additional entries in the column joined on are missing.
The code I'm using is (in a SAS proc SQL):
proc sql;
create table table3 as
select table1.*, table2.*
from table1 full join table2
on table1.id = table2.id;
quit;
Visual example of problem (can't show actual tables as contain sensitive data)
Table 1
id | count1
1 | 2
2 | 3
3 | 2
Table 2
id | count2
1 | 4
2 | 5
3 | 6
4 | 2
Table 3
id | counta | countb
1 | 2 | 4
2 | 3 | 5
3 | 2 | 6
- | - | 2 <----- I want don't want the id column to be blank in this row
I hope I've explained my problem clearly enough, thanks in advance for your help.
The id from table 1 is blank because the row from table2 has no match in table 1. Try looking at the output from this query:
select coalesce(table1.id, table2.id) as id, table1.count1, table2.count2
from table1 full join table2
on table1.id = table2.id;
Coalesce works from left to right returning the first non null value (it can take more than 2 arguments). If the id in table 1 is null it uses the id from table 2 instead
I recommend also to alias all tables in queries, so I’d have written this:
SELECT
COALESCE(t1.id, t2.id) as id,
t1.count1,
t2.count2
FROM
table1 t1
FULL OUTER JOIN
table2 t2
ON
t1.id = t2.id;
Simply select coalesce(t1.id, t2.id), will return the first non-null id value.

Efficient way to map new values to a sql query (i.e 4 columns each with same credentials)

First I am new to Postgres so I may be describing this problem incorrectly so please point me to an answer if it has already been answered.
I have a database with 10 columns. Lets say 4 columns all use the same codes for values (i.e the letter a, b, d, e) I want to rename all of these in the query to what they are matched with values in another table.
I have a very long approach at this stage involving a nested With statements. Is there a easy way to go from say:
table1:
id | col1 | col2 | col3 | col4
------+------+------+------+------
Row_1 | a | c | d | e
Row_2 | c | c | c | c
Row_3 | e | d | d | c
Lookup Table:
code | value
-----+---------
a | apple
b | banana
c | catfish
d | dog
e | egg
Desired result:
Row_1 | apple | catfish | dog | egg
Row_2 | catfish | catfish | catfish | dog
Row_3 | egg | dog | dog | catfish
Yes, https://dba.stackexchange.com/questions/145038/how-to-join-to-the-same-table-multiple-times should basically work for you. But you want an UPDATE, which is a bit different:
Either way, code values in table lookup have to be UNIQUE for obvious reasons.
Updating a single column is simple:
UPDATE table1 t
SET col1 = l.value
FROM lookup l
WHERE t.col1 = l.code;
If no match is found, the row it table1 is not updated.
But running separate updates for every column is considerably more expensive than updating all columns at once - which is a bit more tricky:
UPDATE table1 t
SET col1 = COALESCE(l1.value, t.col1)
, col2 = COALESCE(l2.value, t.col2)
, col3 = COALESCE(l3.value, t.col3)
, col4 = COALESCE(l4.value, t.col4)
FROM table1 t1
LEFT JOIN lookup l1 ON t.col1 = l1.code
LEFT JOIN lookup l2 ON t.col2 = l2.code
LEFT JOIN lookup l3 ON t.col3 = l3.code
LEFT JOIN lookup l4 ON t.col4 = l4.code
WHERE t1.id = t.id;
In this case, all rows are updated. While there can be NULL values in table1 or missing values in lookup we need LEFT [OUTER] JOIN to not exclude rows from the update. So we need another instance of table1 in the FROM clause and LEFT JOIN to that.
And the added COALESCE retains the original value for each individual column where no match was found. The optimal query depends on details not disclosed in your question ...
You might add another WHERE clause to exclude rows where nothing changes. See:
How do I (or can I) SELECT DISTINCT on multiple columns?

Delete a row from resultset in sql

I am trying to run the below query. for a reason i need to join different tables which includes the results from all tables.
Let's say the query is :
Select a.value1, b.value2, c.value3
from a
join b on a.some_value = b.some_value1
join c on c.Some_other_value = b.some_diff_value
where (my conditions)...
Let's say the result of the above query is :
value1 | value2 | value3
-------+--------+--------
1 | val1 | val2
1 | some1 | some2
2 | othr1 | othr2
3 | diff2 | diff3
I want to remove the values from the above result set which value1 is not 1.
Expected output:
value1 | value2 | value3
-------+--------+--------
1 | val1 | val2
1 | some1 | some2
Is there any way in postgresql that I can achieve this? Searched for different threads but no clue in any other posts. Any suggestions are appreciated.
Note: I cannot use where a.value1 = 1 as the logic in the SQL query will result in losing some records for doing math. So the whole idea is to run the SQL query as is but to remove the records after the Select operation is done and just have the result with value1 = 1.
use subquery and then filter out a.value1=1 in where clause
select * from
(
Select a.value1,b.value2,c.value3
from a join b on a.some_value=b.some_value1
join c on c.Some_othr_value=b.some_diff_value
where your conditions
)AA where a.value1=1

Left Outer Join, No result in final query

I'm executing the following query
Select * from A a left outer join B b on (b.id = a.id)
I'm getting one record from A and no records from B. I'm expecting one record in final select query but getting none.
Here is some sample data:
A
v_id, id, date, d_id
1, 1244578, 02-MAR-11, 1827877
B, no data presented:
e_id,id,amount
What am I doing wrong? How can I get it do like this ?
This should work fine:
Select *
from A a
left outer join B b on b."id" = a."id"
See it in action here:
SQL Fiddle Demo
This will give you:
| V_ID | ID | DATE | D_ID | E_ID | AMOUNT |
----------------------------------------------------------
| 1 | 1244578 | 02-MAR-11 | 1827877 | (null) | (null) |
You are getting one record from Table A this is because table A has only one record and Table B have no record.
In left outer join content of first table is show in result join with second table but in your case second table have no records so final result show null values for that records.

Left Outer Join Not Working?

I have a query pulling data from three tables using LEFT OUTER JOIN for both joins. I need the query to return the left most (Salesrep table) info even if the there is no corresponding data in the two right tables (prescriber and prescriptions, respectively). When I run this query without the date parameters in the WHERE clause, I get the expected return, but as soon as I include the date parameters I get nothing returned where there is no matching data for a salesrep. I need to at least see the salesrep table columns requested in the query.
Here is the query... any help is VERY much appreciated.
SELECT salesrep.salesrepid as SalesRepID,
salesrep.fname as SalesrepFName,
salesrep.lname as SalesRepLName,
salesrep.fname+' '+salesrep.lname as SalesRepFullName,
prescriber.dea_no as PDeaNo,
prescriber.lname+', '+prescriber.fname as DocName,
CONVERT(VARCHAR(8), prescriptions.filldate, 1) as FillDate,
prescriptions.drugname as DrugName,
prescriptions.daysupply as Supply,
prescriptions.qtydisp as QtyDisp,
prescriptions.rx_no as Refill,
prescriptions.copay as Sample,
ROUND(prescriptions.AgreedToPay-(prescriptions.AgreedToPay*.07),2) as AgreedToPay,
prescriptions.carrierid as CarrierID
FROM salesrep
LEFT OUTER JOIN prescriber on salesrep.salesrepid = prescriber.salesrepid
LEFT OUTER JOIN prescriptions on prescriber.dea_no = prescriptions.dea_no
WHERE salesrep.salesrepid = 143 AND
prescriptions.filldate >= '09-01-12' AND
prescriptions.filldate <= '09-17-12'
ORDER BY prescriptions.filldate
You should move the constraints on prescriptions.filldate into the ON condition of the join, and remove it from the where clause:
LEFT OUTER JOIN prescriptions ON prescriber.dea_no = prescriptions.dea_no
AND prescriptions.filldate >= '09-01-12'
AND prescriptions.filldate <= '09-17-12'
Otherwise, entries for which there are no prescriptions end up with nulls in prescriptions.filldate, and the WHERE clause throws them away.
Here you can find a brief description about query processing phases (it's common for most DBMSes). You will find out there, that for OUTER JOIN:
first CARTESIAN JOIN is produced,
than the ON condition is performed on result set producing subset of rows,
after than outer rows are appended with NULLs on inner table's joined columns,
on that result the WHERE clause is applied performing filtering.
When you place the condition within WHERE clause which touches outer tables rows they're all discarded. You should simply place that condition within the ON clause, as that one is evaluated before outer rows are appended.
So, those conditions:
prescriptions.filldate >= '09-01-12' AND
prescriptions.filldate <= '09-17-12'
should be moved into ON clause.
This fiddle can be useful for illustrating that:
a restriction placed in the ON clause is processed before the join, while a restriction placed in the WHERE clause is processed after the join.
Note that does not matter with inner joins, but it matters a lot with outer joins. More details in docs
Table t1
| num | name |
| --- | ---- |
| 1 | a |
| 2 | b |
| 3 | c |
Table t2
| num | value |
| --- | ----- |
| 1 | xxx |
| 3 | yyy |
| 5 | zzz |
Join condition in the ON clause
SELECT * FROM t1
LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';
| num | name | num | value |
| --- | ---- | --- | ----- |
| 1 | a | 1 | xxx |
| 2 | b | | |
| 3 | c | | |
Join condition in the WHERE clause
SELECT * FROM t1
LEFT JOIN t2 ON t1.num = t2.num
WHERE t2.value = 'xxx';
| num | name | num | value |
| --- | ---- | --- | ----- |
| 1 | a | 1 | xxx |
View on DB Fiddle
This is because your prescriptions.filldate inequalities are filtering out your salesrep rows that don't have a value in the prescriptions.filldate column.
So if there are null values (no matching data from the right tables), then the entire row, including the salesrep data is filtered out by the date filters - because the null doesn't fall between the two dates.