I have three declared tables:
Table_1 (default) has group number in common with that both sub Table_2 and Table_3
while Table_2 and Table_3 have dates in common
I am having difficulty in joining both sub tables to T1 without losing data after the first join. Instead of NULL, T1 should still have its inital data after T2 is joined.
I tried:
SELECT *
FROM (
SELECT DISTINCT * from #GRP_TABLE as T1
FULL OUTER JOIN
(SELECT * FROM #PASSEDBOOKINGS) AS T2
on T1.T1_GROUP_NUMBER = T2.T2_GROUP_NUMBER
FULL OUTER JOIN
(SELECT * FROM #FAILBOOKINGS)AS T3
ON T3.T3_GROUP_NUMBER = T1.T1_GROUP_NUMBER
and T3.T3_DATE = T2.T2_DATE
)AS JOINS
WHERE JOINS.T3_DATE = CAST(GETDATE() AS DATE)
OR JOINS.T2_DATE = CAST(GETDATE() AS DATE)
#GRP_TABLE AS T1:
|-------|------------------|
|T1_LINE| T1_GROUP_NUMBER |
|-------|------------------|
| A1 | A110 |
|-------|------------------|
| A1 | A120 |
|-------|------------------|
|A1 |A130 |
|-------|------------------|
|A1 |A140 |
|-------|------------------|
|A1 |A150 |
|-------|------------------|
#PASSEDBOOKING AS T2:
|---------------|-----------|----------|
|T2_GROUP_NUMBER| T2_COUNTS | T2_DATE |
|---------------|-----------|----------|
| A110 | 2 |2019-02-25|
|---------------|-----------|----------|
| A120 | 2 |2019-02-25|
|---------------|-----------|----------|
|A130 |2 |2019-02-25|
|---------------|-----------|----------|
#FAILEDBOOKINGS AS T3:
|---------------|-----------|----------|
|T3_GROUP_NUMBER| T3_COUNTS | T3_DATE |
|---------------|-----------|----------|
| A140 | 1 |2019-02-25|
|---------------|-----------|----------|
| A150 | 1 |2019-02-25|
|---------------|-----------|----------|
This results in:
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|T1_LINE| T1_GROUP_NUMBER | T2_GROUP_NUMBER |T2_COUNTS | T3_GROUP_NUMBER |T3_COUNTS | T2_DATE | T3_DATE |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
| NULL | NULL | NULL | NULL | A140 | 1 | NULL | 2019-02-25 |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
| NULL | NULL | NULL | NULL |A150 | 1 | NULL | 2019-02-25 |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A110 | A110 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A120 | A120 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A130 | A130 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
But I am expecting these results:
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|T1_LINE| T1_GROUP_NUMBER | T2_GROUP_NUMBER |T2_COUNTS | T3_GROUP_NUMBER |T3_COUNTS | T2_DATE | T3_DATE |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
| A1 | A140 | NULL | NULL | A140 | 1 | NULL | 2019-02-25 |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
| A1 | A150 | NULL | NULL |A150 | 1 | NULL | 2019-02-25 |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A110 | A110 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A120 | A120 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
|A1 |A130 | A130 | 2 | NULL | NULL | 2019-02-25 | NULL |
|-------|------------------|------------------|----------|-----------------|-------------|------------------|------------------|
You can try using COALESCE function - so if the data is not present in one table pick it up from another
Thanks
The reason for the null output
Even if T1 table contains A140 and A150 then the corresponding T2 and T3 dates are not the same actually the dates does not exist from your sample data.
To get the expected out put as you mention you can do the following,
SELECT *
From
#GRP_TABLE as T1
Left JOIN
#PASSEDBOOKINGS AS T2
on T1.T1_GROUP_NUMBER = T2.T2_GROUP_NUMBER
Left JOIN
#FAILBOOKINGS AS T3
ON T3.T3_GROUP_NUMBER = T1.T1_GROUP_NUMBER
WHERE T3.T3_DATE = CAST(GETDATE() AS DATE)
OR T2.T2_DATE = CAST(GETDATE() AS DATE)
Looking to your data seems you need left join
SELECT DISTINCT T1.T1_LINE, T1.T1_GROUP_NUMBER
, T2.T2_GROUP_NUMBER , T2.T2_COUNT
, T3.T3_GROUP_NUMBER, T2.T2_COUNTS, T2.T2_DATE, T3.T3_DATE, T3.T3_COUNT
from #GRP_TABLE T1
LEFT JOIN #PASSEDBOOKING T2 ON T1.T1_GROUP_NUMBER = T2.T2_GROUP_NUMBER
LEFT JOIN #FAILEDBOOKINGS AS T3 ON T1.T1_GROUP_NUMBER = T3.T2_GROUP_NUMBER
FULL OUTER JOIN is very expensive, and I don't see a reason to use it here. You have a primary table in which you always want data returned, and two secondary tables - so a classic case of FROM T1 LEFT JOIN T2, T3...
Consider this instead.
SELECT *
FROM #GRP_TABLE as T1
LEFT JOIN #PASSEDBOOKINGS AS T2
on T1.T1_GROUP_NUMBER = T2.T2_GROUP_NUMBER
and T2.T2_DATE = CAST(GETDATE() AS DATE)
LEFT JOIN #FAILBOOKINGS AS T3
ON T3.T3_GROUP_NUMBER = T1.T1_GROUP_NUMBER
and T3.T3_DATE = T2.T2_DATE
I'm not even sure you have to join date to date, given that both tables are limited to one date anyway.:
SELECT *
FROM #GRP_TABLE as T1
LEFT JOIN #PASSEDBOOKINGS AS T2
on T1.T1_GROUP_NUMBER = T2.T2_GROUP_NUMBER
and T2.T2_DATE = CAST(GETDATE() AS DATE)
LEFT JOIN #FAILBOOKINGS AS T3
ON T3.T3_GROUP_NUMBER = T1.T1_GROUP_NUMBER
and T3.T3_DATE = CAST(GETDATE() AS DATE)
Also consider unioning T2 and T3, might make more sense!
SELECT *
FROM #GRP_TABLE as T1
LEFT JOIN (SELECT 'pass' as type, * FROM #PASSEDBOOKINGS WHERE DATE = CAST(GETDATE() AS DATE
UNION
SELECT 'fail' as type, * FROM #FAILBOOKINGS WHERE DATE = CAST(GETDATE() AS DATE
)
T2 on T2.GROUP_NUMBER = T1.GROUP_NUMBER
Related
I have the table, where I need to take the next row after the row which has course 'TA' and flag = 1. For this I created the column rnum (OVER DATE) which may help for finding it
| student | date | course | flag | rnum |
| ------- | ----- | ----------- | ---- | ---- |
| 1 | 17:00 | Math | null | 1 |
| 1 | 17:10 | Python | null | 2 |
| 1 | 17:15 | TA | 1 | 3 |
| 1 | 17:20 | English | null | 4 |
| 1 | 17:35 | Geography | null | 5 |
| 2 | 16:10 | English | null | 1 |
| 2 | 16:20 | TA | 1 | 2 |
| 2 | 16:30 | SQL | null | 3 |
| 2 | 16:40 | Python | null | 4 |
| 3 | 19:05 | English | null | 1 |
| 3 | 19:20 | Literachure | null | 2 |
| 3 | 19:30 | TA | null | 3 |
| 3 | 19:40 | Python | null | 4 |
| 3 | 19:50 | Python | null | 5 |
As a result I should have:
| student | date | course | flag | rnum |
| ------- | ----- | ------- | ---- | ---- |
| 1 | 17:20 | English | null | 4 |
| 2 | 16:30 | SQL | null | 3 |
There are many ways to get your desired result, let's see some of them.
1) EXISTS
You can use the EXISTS clause, specifying a subquery to match for the condition.
SELECT T2.*
FROM #MyTable T2
WHERE EXISTS (
SELECT 'x' x
FROM #MyTable T1
WHERE T1.course = 'TA' AND T1.flag = 1
AND T1.student = T2.student AND T2.rnum = T1.rnum + 1
)
2) LAG
You ca use window function LAG to access previous row for a given order and then filter your resultset with your conditions.
SELECT w.student, w.date, w.course, w.flag, w.rnum
FROM (
SELECT T1.*
, LAG(course, 1) OVER (PARTITION BY student ORDER BY rnum) prevCourse
, LAG(flag, 1) OVER (PARTITION BY student ORDER BY rnum) prevFlag
FROM #MyTable T1
) w
WHERE prevCourse = 'TA' AND prevFlag = 1
3) JOIN
You can self-JOIN your table on the next rnum and keep only the rows who match the right condition.
SELECT T2.*
FROM MyTable T1
JOIN MyTable T2 ON T1.student = T2.student AND T2.rnum = T1.rnum + 1
WHERE T1.course = 'TA' AND T1.flag = 1
4) CROSS APPLY
You can use CROSS APPLY to specify a subquery with the matching condition. It is pretty similar to EXISTS clause, but you will also get in your resultset the columns from the subquery.
SELECT T2.*
FROM #MyTable T2
CROSS APPLY (
SELECT 'x' x
FROM #MyTable T1
WHERE T1.course = 'TA' AND T1.flag = 1
AND T1.student = T2.student AND T2.rnum = T1.rnum + 1
) x
5) CTE
You can use common table expression (CTE) to extract matching rows and then use it to filter your table with a JOIN.
;WITH
T1 AS (
SELECT student, rnum
FROM #MyTable T1
WHERE T1.course = 'TA' AND T1.flag = 1
)
SELECT T2.*
FROM #MyTable T2
JOIN T1 ON T1.student = T2.student AND T2.rnum = T1.rnum + 1
Adding the rownumber was a good start, you can use it to join the table with itself:
WITH matches AS (
SELECT
student,
rnum
FROM table
WHERE flag = 1
AND course = 'TA'
)
SELECT t.*
FROM table t
JOIN matches m
on t.student = m.student
and t.rnum = m.rnum + 1
How can I create a query where I can update the table1 column date that I get it on table2?
Here is some example of the tables
Table1:
| stud_id | start_date | birt_date | name | exam_date |
| s001 | 11/19/2018 | 05/20/1999 | john | 10/20/2018 |
| s003 | 01/01/2018 | 05/25/1995 | mike | 10/20/2018 |
| s005 | 12/23/2018 | 02/20/1999 | ed | 10/20/2018 |
| s005 | 12/23/2018 | 02/20/1999 | ed | 10/05/2017 |
Table2:
| stud_id | start_date | exam_date |
| s005 | 01/01/2017 | 10/20/2018 |
| s001 | 01/01/2017 | 10/20/2018 |
| s003 | 01/01/2017 | 10/20/2018 |
Basically I want to change just the start_date of the 3 so s006 will not change.
How can I accomplish that using query? I was thinking using in then select the table but I think its not gonna work.
I need to based on two or more column for the condition of my update so I want to update the table 1 where table1.stud_id = table2.stud_id and table1.exam_date = table2.exam_date
do join and update
update t1
set t1.stardate=t2.startdate,
t1.exam_date=t2.exam_date
from table1 t1 join table2 t2
on t1.stud_id=t2.stud_id
where t2.stud_id='s003' -- if you just need s003 update
You can also use CTE as well to update:
;With cte as
(
select t1.start_date as t1date,t2.start_date as t2date from table1 t1
join table2 t2
on t1.stud_id=t2.stud_id
and t1.exam_date=t2.exam_date
)
update cte set t1date=t2date
You can join the 2 tables:
UPDATE T1
SET Start_Date = T2.Start_Date
FROM Table1 AS T1
INNER JOIN Table2 AS T2
ON T1.stud_id = T2.stud_id
AND T1.exam_date = T2.exam_date
How to join conditionally on (1) full key OR (2) part of the key, if first condition is not met. Suppose id consists of 7 characters.
select
a.id,
coalesce (t.somevalue, t2.somevalue)
from a
left join t
on a.id=t.id
left join t as t2
on left(a.id,6)=left(t2.id,6)
Is the above join possible in one shot? Something like this but maintaining priority of full key join over part key join?
left join t
on
a.id=t.id OR left(a.id,6)=left(t2.id,6)
I wonder if there is something like
left join t
on
case when condition 1
case when condition 2
Here is sample data and expected results.
+---------+
| a.id |
+---------+
| aaaaa0A |
| aaaaa0B |
| aaaaa1A |
| aaaaa2A |
| aaaaa3B |
+---------+
+---------+
| t.id |
+---------+
| aaaaa0C |
| aaaaa1B |
| aaaaa1A |
| aaaaa2B |
| aaaaa3A |
+---------+
+---------+---------+--------------+
| a.id | t.id | condition no |
+---------+---------+--------------+
| aaaaa0A | aaaaa0C | 2 |
| aaaaa0B | aaaaa0C | 2 |
| aaaaa1A | aaaaa1A | 1 |
| aaaaa2A | aaaaa2B | 2 |
| aaaaa3B | aaaaa3A | 2 |
+---------+---------+--------------+
I think you want outer apply:
select a.id, t.somevalue
from a outer apply
(select top (1) t.*
from t
where left(a.id, 6) = left(t.id, 6)
order by (case when a.id = t.id then 1 else 2 end) -- put full matches first
) t;
You can do a 2nd LEFT join of t under the condition that the 1st join does not match:
select
a.id,
coalesce(t1.id, t2.id) id,
case
when t1.id is not null then 1
when t2.id is not null then 2
else 0
end [condition no]
from a
left join t as t1 on a.id = t1.id
left join t as t2 on t1.id is null and left(a.id, 6) = left(t2.id, 6)
See the demo.
Results:
> id | id | condition no
> :------ | :------ | -----------:
> aaaaa0A | aaaaa0C | 2
> aaaaa0B | aaaaa0C | 2
> aaaaa1A | aaaaa1A | 1
> aaaaa2A | aaaaa2B | 2
> aaaaa3B | aaaaa3A | 2
How can I join Table1 on Table2 on opid, only if the table1's date <= table2's date, AND it has no other matches?
Here are some example tables:
Table1
------------+-------+-----+
date | spend | opid|
------------+-------+-----+
2019-07-05 | 5 | 1 |
------------+-------+-----+
2019-07-07 | 4 | 2 |
------------+-------+-----+
2019-07-08 | 6 | 2 |
------------+-------+-----+
Table2
+------------+-------+-----+
| date | users | opid|
+------------+-------+-----+
| 2019-07-06 | 100 | 1 |
+------------+-------+-----+
| 2019-07-08 | 200 | 2 |
+------------+-------+-----+
Expected Table
+------------+-------+-------+
| date | spend | users |
+------------+-------+-------+
| 2019-07-05 | 10 | 100 |
+------------+-------+-------+
| 2019-07-07 | 4 | null |
+------------+-------+-------+
| 2019-07-08 | 6 | 200 |
+------------+-------+-------+
So 7-July doesn't join, because 8-July has already joined.
I think you should try with inner join.
select t1.id, t1.date, t1.spend, t2.id as table2_id, t2.users
from table1 t1 inner join
table2 t2
on t1.date <= t2.date;
This answers the original version of the question.
I think you want a full join:
select t1.id, t1.date, t1.spend, t2.id as table2_id, t2.users
from table1 t1 full join
table2 t2
on t1.date = t2.date;
Please help me compose a SELECT statement. I have these two tables:
Table1 Table2
---------------- ------------------------------------------------
ID | PName | | ID | NameID | DateActive | HoursActive |
---------------- ------------------------------------------------
1 | Neil | | 1 | 1 | 8/2/2013 | 3 |
2 | Mark | | 2 | 1 | 8/3/2013 | 4 |
3 | Onin | | 3 | 2 | 8/2/2013 | 2 |
---------------- | 4 | 2 | 8/6/2013 | 5 |
| 5 | 3 | 8/7/2013 | 1 |
| 6 | 3 | 8/8/2013 | 10 |
------------------------------------------------
And I just want to retrieve the earliest DateActive but no duplicate PName. Like this:
PName | DateActive | HoursActive |
----------------------------------------
Neil | 8/2/2013 | 3 |
Mark | 8/2/2013 | 2 |
Onin | 8/7/2013 | 1 |
----------------------------------------
Something like this might do it. You need to find the min date for each NameID first, then join back to the table to get the hours.
SELECT
PName, MaxDate as DataActive, HoursActive
From
Table1 t1
inner Join Table2 t2 on t1.ID = t2.NameID
Inner Join (Select min(DateActive) as mindate, NameID from Table2 Group by NameID) as t3 on t3.mindate = t2.ActiveDate and t3.NameID = t2.NameId
This should be a pretty standard solution:
select t.pname,
t2.dateactive,
t2.hoursac
from table1 t
join table2 t2 on t.id = t2.nameid
join (
select nameid, min(dateactive) mindateactive
from table2
group by nameid
) t3 on t2.nameid = t3.name
and t3.mindateactive = t2.dateactive
If you are using an RDBMS that supports partition by statements, then this would be more efficient:
select pname, dateactive, HoursActive
from (
select t.pname,
t2.dateactive,
t2.hoursactive,
rank() over (partition by t.id order by t2.dateactive) rownum
from table1 t
join table2 t2 on t.id = t2.nameid
) t
where rownum = 1