I am looking to do a full outer join in order to get the following results. Mainly I am joining table 1 to table 2.
However in table 1, anything that has a 0 in Column A but has the same available value in Key 1 column (ABC100 Key 1 value in table 1), only use that record (record 1 in table 1), and ignore 0 record (record 2 in table 1)
When joined to table 2, specifically for ABC100, I am expecting to see output lines 1 and 2 in the expected table results.
Any help or ideas going about this?
Example:
Table 1
| Key 1 | Column A |
| ABC100 | 100 |
| ABC100 | 0 |
| ABC300 | 200 |
| ABC400 | 300 |
Table 2
| Key 2 | Column C |
| ABC100 | 100 |
| ABC200 | 50 |
| ABC300 | 200 |
Expected results:
| Key 1 | Column A | Key 2 | Column B | NVL(A,0) - NVL(B,0)
| ABC100 | 100 | ABC100 | 100 | 0
| ABC100 | NULL | NULL | NULL | NULL
| NULL | NULL | ABC200 | 50 | -50
| ABC300 | 200 | ABC300 | 200 | 0
| ABC400 | 300 | NULL | NULL | 300
Your result set suggests that you want something like this:
SELECT t1.key1,
(CASE WHEN t1.a <> 0 THEN t1.a END) as a,
(CASE WHEN t1.a <> 0 THEN t2.key2 END) as key2,
(CASE WHEN t1.a <> 0 THEN t2.c END) as ,
(CASE WHEN t1.a <> 0 THEN COALESCE(t1.A, 0) - COALESCE(t2.B, 0) END) as diff
FROM t1 FULL JOIN
t2
ON t1.Key1 = t2.Key2;
Your description suggests that you want:
SELECT t1.key1, t1.a, t2.key2, t2.c,
COALESCE(t1.A, 0) - COALESCE(t2.B, 0) as diff
FROM (SELECT t1.*
FROM
WHERE t1.A <> 0 OR
NOT EXISTS (SELECT 1 FROM t1 tt1 WHERE tt1.key1 = t1.key1 AND tt1.key1 <> 0)
) t1 FULL JOIN
t2
ON t1.Key1 = t2.Key2;
You could use:
SELECT t1.*, t2.*, NVL(t1.A,0) - NVL(t2.B,0)
FROM tab1 t1
FULL JOIN tab2 t2
ON t1.Key1=t2.Key2
Related
I have first table T1 in SAP HANA DB like this:
T1
----------------------------
| key | value | date |
----------------------------
| 1 | A | 01-02-2018 |
| 2 | B | 01-03-2017 |
| 3 | C | 01-02-2017 |
| 4 | D | 01-02-2018 |
----------------------------
And the other table T2:
T2
---------------------
| value | date |
----------------------
| B | 01-02-2017 |
| B | 01-05-2017 |
| D | 01-02-2019 |
----------------------
I need to add to T1 new column as indicator with value '1' if T1.value exists in T2.value and T2.date < T1.date for this value, else '0'. I can only use select query or SQL script for this, with no insert or update statements.
Expected result:
----------------------------------------
| key | value | date | indicator |
----------------------------------------
| 1 | A | 01-02-2018 | 0 |
| 2 | B | 01-03-2017 | 1 |
| 3 | C | 01-02-2017 | 0 |
| 4 | D | 01-02-2018 | 0 |
-----------------------------------------
Please, help with query or script on HANA SQL.
I need to add to T1 new column as indicator with value '1' if T1.value
exists in T2.value and T2.date < T1.date for this value, else '0'.
This is solved with EXISTS:
select
t1.*,
case
when exists (
select 1 from t2
where value = t1.value and date < t1.date
) then '1'
else '0'
end indicator
from t1
You can use a correlated subquery
select T1.*,
( select sign(count(1)) from T2 where T2.date < T1.date and T2.value = T1.value )
as indicator
from T1;
The sign() function returns 1 provided there's at least one row satisfying the condition
Demo
i have my table:
ID | NAME | TYPE
1 | A | 1
2 | A | NULL
3 | B | NULL
4 | C | 2
5 | D | NULL
6 | D | NULL
and i want to for example if i choose Type 1 i get the row but i want all the null values from the other.
ID | NAME | TYPE
1 | A | 1
3 | B | NULL
5 | D | NULL
6 | D | NULL
sometime like this. i try with union but i get repeat A | NULL
thx for all
You seem to want:
select t.*
from t
where type = 1
union all
select t.*
from t
where type is null and
not exists (select 1 from t t2 where t2.name = t.name and t2.type = 1);
You don't actually need the union all:
select t.*
from t
where type = 1 or
(type is null and
not exists (select 1 from t t2 where t2.name = t.name and t2.type = 1)
);
i have 2 tables suppose table_1 & table_2
table_1 has 56 columns and 1.2 million records
my query is like
table_1 like
RollNumber | Subject | G | Part | Status
------------------------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 1
1 | 2 | 1 | 1 | 1
1 | 2 | 1 | 2 | 5
1 | 3 | 1 | 1 | 0
1 | 3 | 1 | 2 | 1
2 | 1 | 2 | 1 | 1
2 | 1 | 2 | 2 | 1
2 | 2 | 2 | 1 | 1
2 | 2 | 2 | 2 | 1
2 | 3 | 2 | 1 | 1
2 | 3 | 2 | 2 | 1
3 | 1 | 2 | 1 | 1
3 | 1 | 2 | 2 | 1
3 | 2 | 2 | 1 | 1
3 | 2 | 2 | 2 | 1
3 | 3 | 2 | 1 | 0
3 | 3 | 2 | 2 | 1
i want all RollNumber (group by with 2nd and third column) from table_1 where any status is 0 but don't want students who also have status = 5(or other than 1)
i have tried this
select * from table_1 as t1
inner join table_2 as t2
on t1.column2 = t2.column2 and t1.column3 = t2.column3 and t1.column4 = t2.column4
where t1.column1 not in
(select column1 from table_1 where status = 5)
This is the inner most query of my qhole query
i have also tried EXCEPT clause
Both queries take too long to execute
Starting with SQL Server 2008 you can use count() over() to count how many total rows in a given group have a certain value.
In this case you'll want to count the number of status <> 1 per group and to only select rows that belong to a group with a count of 0.
select * from (
select * ,
count(case when status <> 1 then 1 end) over(partition by RollNumber, G) c
from table_1
) t where c = 0
You can use EXISTS in place of NOT IN. This will be faster as there will be a boolean comparison instead of string comparison.
select * from table_1 as t1
inner join table_2 as t2
on t1.column1 = t2.column1 and t1.column2 = t2.column2 and t1.column3 = t2.column3
where not EXISTS
(select 1 from table_1 where status = 5 and t1.column3 = table_1.column3)
Try to use NOT EXISTS instead of NOT IN
SELECT *
FROM table_1 AS t1
INNER JOIN table_2 AS t2
ON t1.column1 = t2.column1 AND t1.column2 = t2.column2 AND t1.column3 = t2.column3
WHERE NOT EXISTS(
SELECT 1
FROM table_1
WHERE status=5 AND column3=t1.column3
)
I want to mass-compare a few hundred fields in MS Access between 2 tables with identical column structures. If there are any differences between the column values, replaces the row in table1 with the new row in table2. If table2 does no longer holds a row that exists in table1, that row should be dropped from table1. All changes to table1 should be logged in tableLOGS.
Take for example:
____table1___ _____table2____ __________tableLOGS__________
| pid | A | B | | pid | A | B | | id | pid | A | B | action |
| 1 | 0 | 0 | | 1 | 0 | 0 | | 1 | 1 | 0 | 0 | add |
| 2 | 0 | 0 | | 2 | 0 | 1 | | 2 | 2 | 0 | 0 | add |
| 3 | 0 | 0 |
After running the desired SQL query, the result should be:
____table1___ _____table2____ __________tableLOGS__________
| pid | A | B | | pid | A | B | | id | pid | A | B | action |
| 1 | 0 | 0 | | 1 | 0 | 0 | | 1 | 1 | 0 | 0 | add |
| 2 | 0 | 1 | | 2 | 0 | 1 | | 2 | 2 | 0 | 0 | add |
| 3 | 2 | 0 | 1 | edit |
| 4 | 3 | 0 | 0 | delete |
I expect this would have to be broken down into 2 separate queries?
Mass-compare rows and update changes Log the changes to tableLOGS This seems like a fairly common task so perhaps MS Access has an easy way of accomplishing this? Thanks for all the help! :)
P.S. I am also open to simply deleting rows from table1 that do not match table2, and INSERT INTO table1 from table2.
This is from memory I didn't actually run this so it may need some fixing. My apologies
Start with the logging for updates
INSERT INTO TableLogs
SELECT A, B
FROM (
SELECT A, B
FROM table2 t2
INNER JOIN table1 t1 ON t1.pid = t2.pid
AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL)
Then update table1 with the updated values
UPDATE table1
INNER JOIN(
SELECT *
FROM table2 t2
INNER JOIN table1 t1 ON t1.pid = t2.pid
AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL) t2
ON table1.pid = t2.pid
Log missing records in table 1
INSERT INTO tablelogs
SELECT A, B
FROM table2
INNER JOIN table1 t1 ON t1.pid = t2.pid AND (t1.A <> t2.a OR t1.B <> t2.B)
WHERE table1.A IS NOT NULL
Delete the missing rows from table1
DELETE table1
WHERE pid NOT IN
(SELECT pid FROM Table2)
You could also put a trigger on table1 to update table logs but its not really best practice.
Hope that helps, like I said I didn't run it yet.
I've got a few tables in an access database:
ID | LocationName
1 | Location1
2 | Location2
ID | LocationID | Date | NumProductsDelivered
1 | 1 | 12/10 | 3
2 | 1 | 01/11 | 2
3 | 1 | 02/11 | 2
4 | 2 | 11/10 | 1
5 | 2 | 12/10 | 1
ID | LocationID | Date | NumEmployees | EmployeeType
1 | 1 | 12/10 | 10 | 1 (=Permanent)
2 | 1 | 12/10 | 3 | 2 (=Temporary)
3 | 1 | 12/10 | 1 | 3 (=Support)
4 | 2 | 10/10 | 1 | 1
5 | 2 | 11/10 | 2 | 1
6 | 2 | 11/10 | 1 | 2
7 | 2 | 11/10 | 1 | 3
8 | 2 | 12/10 | 2 | 1
9 | 2 | 12/10 | 1 | 3
What I want to do is pass in the LocationID as a parameter and get back something like the following table. So, if I pass in 2 as my LocationID, I should get:
Date | NumProductsDelivered | NumPermanentEmployees | NumSupportEmployees
10/10 | | 1 |
11/10 | 1 | 2 | 1
12/10 | 1 | 2 | 1
It seems like this should be a pretty simple query. I really don't even need the first table except as a way to fill in the combo box on the form from which the user chooses which location they want a report for. Unfortunately, everything I've done has resulted in me getting a lot more data than I should be getting. My confusion is in how to set up the join (presumably that's what I'm looking for here) given that I want both the date and locationID to be the same for each row in the result set.
Any help would be much appreciated.
Thanks.
EDIT:
Ok - the answer below didn't quite work, but it did set me on the right track and I was able to use the following query:
SELECT t1.Date, t2.NumProductsDelivered,
(SELECT t1a.NumEmployees
FROM table3 t1a
WHERE t1a.EmployeeType=1 AND t1a.LocationID=t1.LocationID AND t1a.Date= t1.Date)
AS "PermEmps",
(SELECT t1b.NumEmployees
FROM table3 t1b
WHERE t1b.EmployeeType=3 AND t1b.LocationID=t1.LocationID AND t1b.Date=t1.Date)
AS "SupportEmps"
FROM table3 AS t1 LEFT JOIN table2 AS t2 ON (t2.Date=t1.Date)
AND (t2.LocationID=t1.LocationID)
WHERE t1.LocationID=2
GROUP BY t1.Date, t1.LocationID, t2.NumProductsDelivered;
This is getting me the results I was looking for. However, in a case where the location has a break between products being delivered, I don't see the correct results. It seems that the recordset stops as soon as there's an empty row and then never picks back up again. So, where I might expect to see this:
Date | NumProductsDelivered | NumPermanentEmployees | NumSupportEmployees
10/10 | | 1 |
11/10 | 1 | 2 | 1
12/10 | 1 | 2 | 1
01/10 | 2 | | 1
06/10 | 1 | |
I only see this:
Date | NumProductsDelivered | NumPermanentEmployees | NumSupportEmployees
10/10 | | 1 |
11/10 | 1 | 2 | 1
12/10 | 1 | 2 | 1
01/10 | 2 | | 1
I think this would work:
DECLARE #LocationId int
SET #LocationId=2
SELECT L2.LocationId, L2.Date, COUNT(DISTINCT NumProductsDelivered) as NumProductsDelivered,
SUM(case when L2.EmployeeType =1 then NumEmployees else 0 end) as NumPermanentEmployees,
SUM(case when L2.EmployeeType =3 then NumEmployees else 0 end) as NumSupportEmployees
FROM L1
RIGHT JOIN L2
ON L1.LocationID=L2.LocationID
AND L1.Date=L2.Date
WHERE L2.LocationId=#LocationId
GROUP BY L2.LocationId, L2.Date
Something like this should work:
[deleted original]
Try this instead (untested):
select t3.date, t2.numproductsdelivered,
(select sum(t3.numemployees)
from table3 t3a
where t3a.locationid = t3.locationid and t3a.date = t3.date and t3a.employeetype = 1
) as numpermanentemployees,
(select sum(t3.numemployees)
from table3 t3b
where t3b.locationid = t3.locationid and t3b.date = t3.date and t3b.employeetype = 3
) as numsupportemployees
from table3 as t3
left join table2 as t2 on t2.locationid = t3.locationid and t2.date = t3.date
where t3.locationid = 2
group by t3.date, t2.numproductsdelivered
If you didn't mind having separate rows for each employee type it could be simplified:
select t3.date, t2.numproductsdelivered, t3.employeetype, sum(t3.numemployees) as numemployees
from table3 as t3
left join table2 as t2 on t2.locationid = t3.locationid and t2.date = t3.date
where t3.locationid = 2 and t3.employeetype in (1, 3)
group by t3.date, t2.numproductsdelivered, t3.employeetype
Edit: Try this query:
SELECT t1.Date
FROM table3 AS t1
WHERE t1.LocationID=2
GROUP BY t1.Date
...and see if you get all the dates.
Then add the left join:
SELECT t1.Date, t2.NumProductsDelivered
FROM table3 AS t1 LEFT JOIN table2 AS t2 ON (t2.Date=t1.Date)
AND (t2.LocationID=t1.LocationID)
WHERE t1.LocationID=2
GROUP BY t1.Date, t1.LocationID, t2.NumProductsDelivered;
If it's doing a left INNER join, then it will remove rows from t1 that don't have a matching row in t2. Try explicitly setting a left OUTER join and see if that works. The RDBMS I've used the most defaults to outer, but maybe yours (Access) defaults to inner.
So I am thinking the following will work (add "OUTER" and remove "t1.LocationId"):
SELECT t1.Date, t2.NumProductsDelivered,
(SELECT t1a.NumEmployees
FROM table3 t1a
WHERE t1a.EmployeeType=1 AND t1a.LocationID=t1.LocationID AND t1a.Date= t1.Date)
AS "PermEmps",
(SELECT t1b.NumEmployees
FROM table3 t1b
WHERE t1b.EmployeeType=3 AND t1b.LocationID=t1.LocationID AND t1b.Date=t1.Date)
AS "SupportEmps"
FROM table3 AS t1 LEFT OUTER JOIN table2 AS t2 ON (t2.Date=t1.Date)
AND (t2.LocationID=t1.LocationID)
WHERE t1.LocationID=2
GROUP BY t1.Date, t2.NumProductsDelivered;