Left join behavior - sql

I have a small query below. #t1 and #t2 are 2 little tables. I am trying to do a simple left join for both these tables and I see the output.
query:
create table #t1 (cid int, program varchar(20), PP varchar(20), Startdate date, enddate date,codeset varchar(20),visitID int)
insert into #t1
values
(1001,'P1','ORD','2018-09-27','2018-09-28','OL',150),
(1001,'P2','ORD','2018-09-29',NULL,'IR',151)
create table #t2 (cid int,visitID int, answer varchar(20))
insert into #t2
values
(1001,150,'Credited')
select t1.cid, t1.Startdate, t1.Enddate,t2.answer
from #t1 t1
left join #t2 t2 on t1.cid = t2.cid
drop table #t1, #t2
The output is:
To the logic of left join, all the records from left table and only matching records from the right table should show up. Why do I see 'Credited' in the second row when no such record exist in #t1?
desired output:
I'm missing something silly and unable to figure out. Any help?!

You are seeing the expected behavior. You are joining on CID. The single record in #t2 has a CID value of 1001. That matches both records in #t1 since both records in #t1 have value of 1001; thus, you have two rows in your results with a value of Credited for the column answer.

You apparently want to join cid and visitid.
SELECT t1.cid,
t1.startdate,
t1.enddate,
t2.answer
FROM #t1 t1
LEFT JOIN #t2 t2
ON t1.cid = t2.cid
AND t1.visitid = t2.visitid;

I don't think you can get such output with data and join condition you have. You are joining #t1 to #t2 by cid and you have the same cid for both records in #t2 table thats mean that one record from the #t2 with cid 1001 will be joined to both of records in table #t2.
You can get such output if you will change id of second line in #t1 to 1002 but I don't know is it correct for your task.

If you want to only show Credited where there is an EndDate specified, you need to add to your join condition.
select t1.cid, t1.Startdate, t1.Enddate,t2.answer
from #t1 t1
left join #t2 t2 on t1.cid = t2.cid AND t1.EndDate IS NOT NULL
If it's the visitID and not the EndDate that causes this, then use this query:
select t1.cid, t1.Startdate, t1.Enddate,t2.answer
from #t1 t1
left join #t2 t2 on t1.cid = t2.cid AND t1.visitId = 150
We don't have enough info right now to really know what your logic requires but it will likely look something like the above.

Related

How to 1st table distinct and sum and join 2nd table, which if not match between T1 and T2 then add new row

How to join 1st table distinct and sum and join 2nd table, which if not match between T1 and T2 then add new row
Result i need
Period in result table is Getdate()
Select distinct(y.Emp_ID),x.MealAllowance_OT from [dbo].[SPCM_TX_MonthlyAllowance] y left join
(Select x.Emp_Id,x.MealAllowance_OT from [dbo].[SPCM_Cal_OTLog] x
group by x.Emp_Id,x.MealAllowance_OT) x
on x.Emp_Id = y.Emp_ID
order by x.MealAllowance_OT desc
You have to use a subquery on T2 to get sums by group. Then you outer join with T1 to include non-matching rows.
I guessed at the math and the defaults. Like why is Pay/MealAllowance presumed to be 400 when there isn't an entry in T1.
declare #T1 table (Emp_Id int, TRA varchar(3), Pay int)
declare #T2 table (Emp_Id int, DayTy varchar(3), MealAllowance int)
insert into #T1
values (1,'DL',400),(2,'IDL',400),(5,'IDL',400)
insert into #T2
values (1,'DL',18),(2,'IDL',136),(2,'IDL',136),(4,'IDL',136)
select isnull(T1.Emp_Id,T2.Emp_Id) Emp_Id,isnull(T1.TRA,T2.DayTy) DayTY
,isnull(Pay,400) MealAllowance_Mont, isnull(MealAllowance,0) MealAllowance
,isnull(Pay,400) + isnull(MealAllowance,0) Tot, getdate() period
from #T1 T1
full outer join
(
select Emp_Id, DayTy,sum(MealAllowance) MealAllowance
from #T2
group by Emp_Id, DayTy
) T2
on T1.Emp_Id = T2.Emp_Id
and T1.TRA = T2.DayTy

Conditional condition when joining tables in SQL Server

I have two tables both containing employee data, TableA and TableB, I'm joining them based on 2 id's (one it's userID and the other mID (month based id)) using a LEFT OUTER JOIN which returns NULL in about 20% of the results because TableB it's incomplete. I want -if possible- a query that detects if the join doesn't find a match and subtract one month to mID so the JOIN can cover at least a percentage of missing data with just old data.
I don't know if it's a way too complex query but I had in mind something like:
SELECT T1.*, T2.*
FROM TABLEA
LEFT OUTER JOIN TABLEB
ON T2.USERID = T1.USERID AND (CASE WHEN (T2.HID = T1.HID) = NULL THEN (T2.HID = T1.HID-1))
Appreciate any help.
I think this is what you are really wanting to do; the downside is there is a bit more logic and it would be duplicated per column, but it provides a fine grain of control.
DECLARE #TableA TABLE (USERID INT,HID INT,SomeData VARCHAR(20))
DECLARE #TableB TABLE (USERID INT,HID INT,SomeData VARCHAR(20))
INSERT INTO #TableA(USERID,HID,SomeData) SELECT 1,5,'Now'
INSERT INTO #TableA(USERID,HID,SomeData) SELECT 2,5,NULL
INSERT INTO #TableA(USERID,HID,SomeData) SELECT 3,5,NULL
INSERT INTO #Tableb(USERID,HID,SomeData) SELECT 2,4,'Now-1'
INSERT INTO #Tableb(USERID,HID,SomeData) SELECT 2,3,'Now-2'
INSERT INTO #Tableb(USERID,HID,SomeData) SELECT 3,4,'Now-1'
SELECT
t1.USERID, T1.Hid AS [Current HID]
,
CASE
WHEN T1.SomeData IS NOT NULL THEN T1.SomeData
WHEN T2.USERID IS NOT NULL THEN T2.SomeData
WHEN T3.USERID IS NOT NULL THEN T3.SomeData
ELSE T1.SomeData
END AS [Most Recent SomeData]
FROM #TABLEA T1
LEFT JOIN #TABLEB T2 ON T2.USERID = T1.USERID AND T2.HID = T1.HID
LEFT JOIN #TABLEB T3 ON T3.USERID = T1.USERID AND T3.HID = T1.HID-1
You were on the right track by using a case statement but it was just a little out of order. Warning! I didn't test it but I believe I ran into something similar in the past.
SELECT T1.*
,T2.*
FROM TABLEA t1
LEFT JOIN TABLEB t2 ON T2.USERID = T1.USERID
AND T2.HID = CASE
WHEN T2.HID = T1.HID then t1.hid
else T1.HID - 1
end

Alternative way of using DISTINCT in SQL Server 2008

I have a table with millions of rows of data in SQL Server 2008. I am trying to find an alternative way instead of using distinct. Please see the query below:
create table #temp (id int)
create table #temp2 (id int, name varchar(55), t_id int)
insert into #temp values (1)
insert into #temp2 values (1,'john',1)
insert into #temp2 values (2,'alex',1)
insert into #temp2 values (3,'alex',1)
select t.id, t2.name
from #temp t
inner join #temp2 t2 on t.id = t2.t_id
This query returns output like:
Id Name
1 john
1 alex
1 alex
The expected output is:
Id Name
1 john
1 alex
I can provide the expected output by using DISTINCT keyword, I know it, but it decreases the performance. Could you please advise me some professional alternative ways (except using group by) to handle it? Thanks!
Edit:
I have a custom concentenate function which helps me to do:
select t.id, concetenate(t2.name)
from #temp t
inner join #temp2 t2 on t.id = t2.t_id
and this is returning 1 john,alex,alex. I am looking for a way to get rid of one of the alex without updating the function and do not want to use "distinct" keyword.
Use GROUP BY
select t.id, t2.name
from #temp t
inner join #temp2 t2 on t.id = t2.t_id
GROUP BY t.id, t2.name
Use a CTE and ROW_NUMBER and your custom "concetenate" function
;WITH cte
AS(
select t.id, t2.name, RN=ROW_NUMBER()OVER(PARTITION BY t2.name ORDER BY t2.id)
from #temp t
inner join #temp2 t2 on t.id = t2.t_id
)
SELECT C.id
, Name =concetenate(C.name)
FROM cte C WHERE C.RN = 1
You can use group by like below - But why you are inserting duplicates in yourtable..
create table #temp (id int)
create table #temp2 (id int, name varchar(55), t_id int)
insert into #temp values (1)
insert into #temp2 values (1,'john',1)
insert into #temp2 values (2,'alex',1)
insert into #temp2 values (3,'alex',1)
select t.id, t2.name
from #temp t
inner join #temp2 t2 on t.id = t2.t_id
GROUP BY t.id, t2.name
Another solution is we can create a constraint to restrict the duplicate values.

Use multiple WITH tablename AS (...) statements SQL Server

I'm trying to create two temporary tables and join them with a permanent table. For example:
WITH temp1 AS (COUNT(*) AS count_sales, ID FROM table1 GROUP BY ID)
WITH temp2 AS (COUNT(*) AS count_somethingelse, ID FROM table2 GROUP BY ID)
SELECT *
FROM table3 JOIN table2 JOIN table1
ON table1.ID = table2.ID = table3.ID
but there seems to be an issue having multiple WITH tablename AS (...) statments. I tried a semicolon.
Your query should look more like this:
WITH temp1 AS (
SELECT COUNT(*) AS count_sales, ID
FROM table1
GROUP BY ID
),
temp2 AS (
SELECT COUNT(*) AS count_somethingelse, ID
FROM table2
GROUP BY ID
)
SELECT *
FROM temp2 JOIN
temp1
ON temp1.ID = temp2.ID;
Your query has multiple errors. I would suggest you start by understanding why this version works -- or at least does something other than report on syntax errors. Then, go back and study SQL some more.
I'm trying to create two temporary tables
Just for clarity... you used a CTE which is not quite the same thing as a temporary table. You've also tagged 'temp tables', so you want a temp table? You can store query results in a declared table variable or an actual temp table.
An example of declared table variables:
DECLARE #table1 TABLE(id int, count_sales int)
INSERT INTO #table1 (id, count_sales)
SELECT ID, COUNT(*)
FROM table1
GROUP BY ID
--or however you populate temp table1
DECLARE #table2 TABLE(id int, count_somethingelse int)
INSERT INTO #table2 (id, count_somethingelse)
SELECT ID, COUNT(*)
FROM table2
GROUP BY ID
--or however you populate temp table2
SELECT T3.id
--,T2.(some column)
--,T1.(some column)
--,etc...
FROM table3 T3 INNER JOIN #table2 T2 ON T3.id = T2.id
INNER JOIN #table1 T1 ON T3.id = T1.id

Left/right join to receive all rows

How can I join two tables together to get all rows from each, and enter NULL, where one is missing in the other one.
For example:
declare #t1 table (x int)
declare #t2 table (x int)
insert into #t1 select 2
insert into #t1 select 3
insert into #t1 select 4
insert into #t1 select 5
insert into #t2 select 1
insert into #t2 select 2
insert into #t2 select 5
select *
from #t1 t1
left join #t2 t2 on t2.x = t1.x
The result should look like this:
t1.x t2.x
NULL 1
2 2
3 NULL
4 NULL
5 5
select *
from #t1 t1
full outer join #t2 t2 on t2.x = t1.x
this is like left join, but will take all the records from both table even when there is no match, and will enter null when there is no match.
select *
from #t1 t1
FULL OUTER join #t2 t2 on t2.x = t1.x
All rows from both tables are returned in a full outer join. SQL Server uses the following ISO keywords for outer joins specified in a FROM clause: LEFT OUTER JOIN or LEFT JOIN. RIGHT OUTER JOIN or RIGHT JOIN. FULL OUTER JOIN or FULL JOIN