How to JOIN and get data from either table based on specific logics? - sql

Let's say I have 2 tables as shown below:
Table 1:
Table 2:
I want to join the 2 tables together so that the output table will have a "date" column, a "hrs_billed_v1" column from table1, and a "hrs_billed_v2" column from table2. Sometimes a date only exists in one of the tables, and sometimes a date exists in both tables. If a date exists in both table1 and table2, then I want to allocate the hrs_billed_v1 from table1 and hrs_billed_v2 from table2 to the output table.
So the ideal result will look like this:
I've tried "FULL OUTPUT JOIN" but it returned some null values for "date" in the output table. Below is the query I wrote:
SELECT
DISTINCT CASE WHEN table1.date is null then table2.date WHEN table2.date is null then table1.date end as date,
CASE WHEN table1.hrs_billed_v1 is null then 0 else table1.hrs_billed_v1 END AS hrs_billed_v1,
CASE WHEN table2.hrs_billed_v2 is null then 0 else table2.hrs_billed_v2 END AS hrs_billed_v2
FROM table1
FULL OUTER JOIN table2 ON table1.common = table2.common
Note that the "common" column where I use to join table1 and table2 on is just a constant string that exists in both tables.
Any advice would be greatly appreciated!

A full join is indeed what you want. I think that would be:
select
common,
date,
coalesce(t1.hrs_billed_v1, 0) as hrs_billed_v1,
coalesce(t2.hrs_billed_v2, 0) as hrs_billed_v2
from table1 t1
full join table2 t2 using (common, date)
Rationale:
you don't show what common is; your data indicates that you want to match rows of the same date - so I put both in the join condition; you might need to adapat that
there should really be no need for distinct
coalesce() is much shorter than the case expressions
using () is handy to express the join condition when the columns to match have the same name in both tables

Related

Comparing base table value with second table's sum of value with group by

I have two tables:
One is base table and second is transaction table. I want to compare base table value with second table's sum of value with group by.
Table1(T1Id,Amount1,...)
Tabe2(T2Id,T1ID,Amount2)
I want those rows from table 1 WHere SUM of Table2's SUM( Amount2) is greater or equal table1's Amount1.
*T1ID is in relation with both tables
* The SQL query have many joins with other table for data retriving.
One approach uses a join:
SELECT t1.T1Id, t1.Amount1
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.T1Id = t2.T1ID
GROUP BY
t1.T1Id, t1.Amount1
HAVING
SUM(t2.Amount2) >= t1.Amount1;
We can also try doing this via a correlated subquery:
SELECT t1.T1Id, t1.Amount1
FROM Table1 t1
WHERE t1.Amount1 <= (SELECT SUM(t2.Amount2) FROM Table2 t2
WHERE t1.T1Id = t2.T1ID);
I would use something similar to the query below:
SELECT
a.T1Id, a.Amount1, SUM(b.Amount2)
FROM Table1 a
INNER JOIN Table2 b on b.T1Id = a.T1Id
GROUP BY a.T1Id, a.Amount1
HAVING SUM(b.Amount2) >= a.Amount1;
Basically what the query above does is give you the ID, Amount from table 1 and the summed amount from table 2. The HAVING clause at the end of query filters out those records where the summed amount from the second table is smaller than the amount from the first one.
If you want to add further table joins to the query, you can do so by adding as many joins as you wish. I would recommend having a referenced ID for each table you are joining in the Table1 table.

Not able to Get data from multiple independent tables that have a common column and yet do not depend on each other

I have 8 tables all with equal number of columns and with a common column. I want to fetch data from all tables in a single query.
My table structure is TABLE1, TABLE2, TABLE3, ..... TABLE 8.
that have columns COLUMNA, COLUMNB... COLUMNE and a COMMON_COLUMN
I need to get data with a where clause where COMMON_COLUMN='X'
I will need all columns from all tables.
I used a query that goes like this..
SELECT TABLE1.*, TABLE2.*, TABLE3.*
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.COMMON_COLUMN = T2.COMMON_COLUMN,
LEFT JOIN TABLE3 T3 ON T1.COMMON_COLUMN = T3.COMMON_COLUMN
WHERE T1.COMMON_COLUMN='X' AND T2.COMMON_COLUMN='X' AND T3.COMMON_COLUMN='X'
The above query is not giving any results even if one of the tables do not have any rows. I do not want to use inner join because although the tables have a common column they do not depend on each other and I need data from all tables with a certain common column.
Also, the tables have unequal number of rows.
What am I doing wrong?
correct me if i am wrong - as you do not attach any sample data and desired result
but i assume that you simply need union all tables. You write in the title that tables are independent
SELECT T1.*
FROM TABLE1 T1
WHERE T1.COMMON_COLUMN='X'
UNION ALL
SELECT T2.*
FROM TABLE2 T2
WHERE T2.COMMON_COLUMN='X'
UNION ALL
SELECT T3.*
FROM TABLE3 T3
WHERE T3.COMMON_COLUMN='X'
...

Using WHERE IS NULL returns all values

I have a query that joins three tables and returns an aliased calculation as a final field. Often that value is null when there's a null in a field that was joined on. The join works well.
I want to return just records where I'm getting Nulls in my calculated field.
But if I add
WHERE field_name IS NULL
to the end I get no records
If I add
WHERE field_name IS NOT NULL
I get the whole set which I can see several records as in fact null
Any explanation on why or how to fix this?
Edit: I found a solution for my case. The field name was an alias for a calculation above. When I duplicated the calculation in the where clause, instead of putting the alias, it ran correctly.
Given an outer join:
select *
from table1
left join table2 on table2.table1_id = table1.id
the way to apply a is null filter to the joined table is to put it in the join condition:
select *
from table1
left join table2 on table2.table1_id = table1.id
and table2.col1 is null
and NOT:
select *
from table1
left join table2 on table2.table1_id = table1.id
where table2.col1 is null
Because if the join misses, all columns in the joined table are null, so using is null in the where will return all rows the joined to row that had a null and all rows that did not join.\
I found a solution for my case. The field name was an alias for a calculation above. When I duplicated the calculation in the where clause, instead of putting the alias, it ran correctly.

SQL Select from case or IF...Then logic?

I'm trying to eliminate making a post pass into the db and in doing so have encountered this problem.
The scenario is that I need to join onto a table that has many rows per item. Think dated values, Item x has a value of n at date y. There's also a row for the same item at date x and z.
I have no influence or power to change this table.
What I'm trying to do is something along the lines of this:
Select
table1.Name as name,
table1.date as date,
if (date > x)
select table2.value as value,
table2.othervalue as otehrvalue
from table 2
where table1.x = table2.x
from table1
but I'm running into difficulties.
I've successfully run the test conditions with strings so if date > x display a string and so on but I can't seem to get the select to work(if possible) and I'm not sure where I'm going wrong. I've looked online and not found much to go on which leads me to think I could be barking up the wrong tree...
We're using Advantage DB.
Any help appreciated
Edited as I'd liek to return more than one value from the sub query...
Use a CASE expression:
select table1.Name as name,
table1.date as date,
case when date > x then
(select table2.value
from table2
where table1.x = table2.x)
end as value
from table1
Will return NULL when date <= x.
Note, if the sub-select returns more than one row you'll get an error!
You can also use case...when with a left outer join:
Select
table1.Name as name,
table1.date as date,
case when table1.date > x
then table2.value
else null
end as value
from table1
left join table2
on table1.x = table2.x;
Edit, Re : Conditionally return multiple columns from table 2
Yes, you should be able to do this for multiple columns, by using the date > x as a join condition, and retaining the left outer join (this will again project NULL's for any failed joins), and finally using COALESCE to revert any NULLs back to the Table1 condition:
Select
table1.Name as name,
table1.date as date,
COALESCE(table2.x, table1.x) as x,
COALSECE(table2.y, table1.y) as y
from table1
left join table2
on table1.x = table2.x AND table1.date > x;

Comparing two datasets SQL SSRS 2005

I have two datasets on two seperate servers. They both pull one column of information each.
I would like to build a report showing the values of the rows that only appear in one of the datasets.
From what I have read, it seems I would like to do this on the SQL side, not the reporting side; I am not sure how to do that.
If someone could shed some light on how that is possible, I would really appreciate it.
You can use the NOT EXISTS clause to get the differences between the two tables.
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
This will show the rows in Table1 that don't appear in Table2. You can reverse the table names to find the rows in Table2 that don't appear in Table1.
Edit: Made an edit to show what the case would be in the event of linked servers. Also, if you wanted to see all of the rows that are not shared in both tables at the same time, you can try something as in the below.
SELECT
Column, 'Table1' TableName
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
UNION
SELECT
Column, 'Table2' TableName
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
NOT EXISTS
(
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
Table1.Column = Table2.Column
)
You can also use a left join:
select a.* from tableA a
left join tableB b
on a.PrimaryKey = b.ForeignKey
where b.ForeignKey is null
This query will return all records from tableA that do not have corresponding records in tableB.
If you want rows that appear in exactly one data set and you have a matching key on each table, then you can use a full outer join:
select *
from table1 t1 full outer join
table2 t2
on t1.key = t2.key
where t1.key is null and t2.key is not null or
t1.key is not null and t2.key is null
The where condition chooses the rows where exactly one match.
The problem with this query, though, is that you get lots of columns with nulls. One way to fix this is by going through the columns one by one in the SELECT clause.
select coalesce(t1.key, t2.key) as key, . . .
Another way to solve this problem is to use a union with a window function. This version brings together all the rows and counts the number of times that key appears:
select t.*
from (select t.*, count(*) over (partition by key) as keycnt
from ((select 'Table1' as which, t.*
from table1 t
) union all
(select 'Table2' as which, t.*
from table2 t
)
) t
) t
where keycnt = 1
This has the additional column specifying which table the value comes from. It also has an extra column, keycnt, with the value 1. If you have a composite key, you would just replace with the list of columns specifying a match between the two tables.