t-sql join help - sql-server

Table_A
TxID RelatedTxID
-------------------
1 NULL
2 NULL
3 1
Table_B
OrderID TxID OrderDescription
-----------------------------------
1 1 Description_1
2 2 Description_2
I want to get an output which will give me order description for the transaction. But if the transaction does not have an order description I want to display it's related transaction's order description (Related transaction will always have an order description)
Output
TxID RelatedTxID OrderDescription
------------------------------------
1 NULL Description_1
2 NULL Description_2
3 1 Description_1
I am thinking of something like below but stuck at what should come in the ISNULL expression.
select
a.TxID,
a.RelatedTxID,
ISNULL(b.OrderDescription, <<get its related transaction's order description>>)
from Table_A a
left outer join Table_B b
on a.TxID = b.TxID
Thanks

select
a.TxID,
a.RelatedTxID,
ISNULL(b1.OrderDescription, b2.OrderDescription)
from Table_A a
left outer join Table_B b1 on a.TxID = b1.TxID
left outer join Table_B b2 on a.RelatedTxID = b2.TxID

Related

Filter out some records on particular periods

I have below tables structures,
Trans Table:
Trans_Id(PK) User_Id(FK) Arroved_Date
________________________________________________
1 101 05-06-2016
2 101 20-06-2016
3 102 06-06-2016
4 103 10-06-2016
5 103 25-06-2016
Table2:
Id(Pk) User_Id(Fk) Start_Date End_Date
__________________________________________________________________
1 101 01-06-2016 15-06-2016
2 103 05-06-2016 20-06-2016
I want to filter out the transaction, if the Approved_Date is not between the users Start_Date and End_Date of table2.
Expected Result:
Trans_Id
________
2
3
5
This query should give you the expected results:
select t1.trans_id from t1
left join t2
on t1.user_id=t2.user_id
where t2.id is null OR t1.Arroved_Date not between t2.Start_Date and t2.End_Date
Try
SELECT Trans_ID
FROM Table1
JOIN Table2 ON Table1.User_Id=Table2.User_Id
where Approved_date Between Start_Date And End_Date
i'm not sure but from you expected output..
SELECT distinct t1.Trans_ID
FROM Table1 t1
LEFT JOIN Table2 t2 on 1=1
where t1.Approved_date Between t2.Start_Date And t2.End_Date
Based on your explanation (not on the expected result) you need to just JOIN the two tables on the FK you pointed out, in order to get the relationship between the rows in the two tables.
Then just apply a WHERE clause to filter the row based on your condition:
select t.trans_id
from trans t
inner join table2 t2 on t.user_id = t2.user_id
where t.approved_date between t2.start_date and t2.end_date
SELECT t.trans_id
FROM Trans tr
LEFT JOIN Table2 t2 ON tr.User_id = t2.User_id
WHERE t2.id IS NULL
OR t.Approved_Date IS NULL
OR t2.Start_Date IS NULL
OR t2.End_Date IS NULL
OR tr.Approved_Date <= t2.Start_Date
OR tr.Approved_Date >= t2.End_Date
The null-checks are only needed if the columns are nullable. The left join can be changed to an inner join if every transaction has a corresponding row in table 2. The answer assumes that there is not more than one row in table 2 for each transaction.
Try this one.
SELECT A.Trans_ID
FROM TEMP A
JOIN TEMP B ON A.User_Id = B.User_Id
WHERE A.Approved_date BETWEEN Start_Date AND End_Date

which one is better:Filter on join clause or Filter on where clause when joining two table?

I am trying to join 2 or more tables on MS SQL Server. All the tables have IsActive field which determines the active record. (IsActive = 1 means active record and IsActive = 0 means inactive record or record has been deleted from system)
So I have two conditions for joining the two or more tables.
On The first query,I filter the IsActive on the join clause
select * from table_A a
inner join table_B b
on a.ID = b.ID and b.IsActive = 1
inner join table_C c
on b.ID = c.ID and c.IsActive = 1
where a.IsActive = 1
On The second query, I also can filter IsActive on the where Clause
select * from table_A a
inner join table_B b
on a.ID = b.ID
inner join table_C c
on b.ID = c.ID
where a.IsActive = 1 and b.IsActive = 1
and c.IsActive = 1
notes: The relation from table A to B is one to one but from table A to C is one to many and also all the table has clustered index on primary key ID and the ID is auto increment.
So which one do you think is better? (assume each table has approximately 100.000 records (80% active records and 20% inactive records))
Thanks
The difference is simple but takes a careful eye to spot.
Consider the following example:
create table tbl_client as
select 1 as client_id, 'aaa' as client_name, 'Y' is_active from dual
union all
select 2, 'bbbbb', 'N' from dual
union all
select 3, 'cc', 'Y' from dual;
create table tbl_transaction as
select 1 transaction_id, 1 client_id, 123.34 amount from dual
union all
select 2, 1, 4353.45 from dual
union all
select 3, 2, 251.48 from dual;
Now, on these tables run the followoing queries:
Inner Join:
In an inner join, there is no difference in the results of the following two queries:
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- filter on join
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- filter in where
Both their result is the same as:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
Left Outer Join
This is where the difference kicks in.
Consider the following query:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- << filter in join
Result:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
cc -- << Note that client cc's transaction record is not there
bbbbb -- << and this client also shows up
And when you apply filter on where in a left outer join:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- << filter in where
Result:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y -- No row for bbbbb or cc clients, just like the inner join
Summary
In short, when you put a filter on the joining condition, the filter is applied to the table being joined. For example, in the first case in the left outer join section, the row for tbl_transaction didn't show up for the client bbbbb.
But when you put a filter in the where clause, it filters the entire data set that is retrieved after joining all the tables (logically. Internal technical operations differ across RDBMSes). This is why the rows for bbbbb and cc didn't show up in the last query.
Fiddle
EDIT
As #DanGuzmanSqlServerMvp has mentioned in his comment, for the example you have posted in your question, the SQL Server query optimizer should execute the same plan. However, if there was an outer join in your query, the plans would be different.

Query writing issue in SQL Server 2008

Table_A: Table_B:
Column_A Column_A Value EmpId
A A 1 1
B B 2 1
C - - -
D - - -
I have 2 tables as you can show above. I want to get all the records of Table_A related to the EmpId
My Expected Result related to EmpId - 1:
Column_A Value
A 1
B 2
C null
D null
I have used the below query:
Select * from Table_A a left join Table_B b on a.Column_A = b.Column_B
The above query will give my expected result but it as you can see it is not filtered on the basis of EmployeeId. Can anyone help me. Thanks
ANY QUICK HELP PLEASE
Select a.Column_A, b.Value
from Table_A a
left join Table_B b on a.Column_A = b.Column_B
and b.EmpID = 1
Should give you the expected results.
If you want to apply filters of EmpID, then just add where clause,
Select * from Table_A a
left join Table_B b on a.Column_A = b.Column_B
where b.EmpId = 1

Using Joins to get all data from left table

I have two tables as shown below.
Id Name Id Status
-------- -------------------
1 A 1 Approved
2 B 6 Approved
3 C 4 Pending
4 D 1 Approved
5 E 1 Pending
6 F 3 Pending
5 Rejected
Now this is how I want the output to be:
Id Name Status
-------------------
1 A Pending
2 B
3 C Pending
4 D Pending
5 E
6 F
I have tried using left join but I am getting multiple rows.
select t1.ID,Name,Status from t1 left join t2 on t1.id=t2.id
and if I add where Status=pending i am getting only ids 1 and 3.
Here are the queries i tried:
select distinct t1.id,name,status from t1 left join t2 on t1.id=t2.id (this gives me duplicate records i.e id 1 is occurs twice with approved and pending)
and also
select distinct t1.id,name,status from t1 left join t2 on t1.id=t2.id where t2.status='pending' (gives me only 1,3 and 4)
Could any one help me,
Thanks in advance.
To include all rows from T1 and only those from T2 with status = 'pending' move the condition into the ON clause SQL Fiddle
SELECT t1.ID,
Name,
Status
FROM t1
LEFT JOIN t2
ON t1.id = t2.id
AND t2.status = 'pending'
To only return one row per id in the event of dupes you could do (Fiddle)
WITH CTE AS
(
SELECT DISTINCT id, Status
FROM T2
WHERE Status = 'Approved'
)
SELECT t1.ID,
Name,
Status
FROM t1
LEFT JOIN CTE
ON t1.id = CTE.id

Limited T-SQL Join

This should be simple enough, but somehow my brain stopped working.
I have two related tables:
Table 1:
ID (PK), Value1
Table 2:
BatchID, Table1ID (FK to Table 1 ID), Value2
Example data:
Table 1:
ID Value1
1 A
2 B
Table 2:
BatchID Table1ID Value2
1 1 100
2 1 101
3 1 102
1 2 200
2 2 201
Now, for each record in Table 1, I'd like to do a matching record on Table 2, but only the most recent one (batch ID is sequential). Result for the above example would be:
Table1.ID Table1.Value1 Table2.Value2
1 A 102
2 B 201
The problem is simple, how to limit join result with Table2. There were similar questions on SO, but can't find anything like mine. Here's one on MySQL that looks similar:
LIMITing an SQL JOIN
I'm open to any approach, although speed is still the main priority since it will be a big dataset.
WITH Latest AS (
SELECT Table1ID
,MAX(BatchID) AS BatchID
FROM Table2
GROUP BY Table1ID
)
SELECT *
FROM Table1
INNER JOIN Latest
ON Latest.Table1ID = Table1.ID
INNER JOIN Table2
ON Table2.BatchID = Latest.BatchID
SELECT id, value1, value2
FROM (
SELECT t1.id, t2.value1, t2.value2, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t2.BatchID DESC) AS rn
FROM table1 t1
JOIN table2 t2
ON t2.table1id = t1.id
) q
WHERE rn = 1
Try
select t1.*,t2.Value2
from(
select Table1ID,max(Value2) as Value2
from [Table 2]
group by Table1ID) t2
join [Table 1] t1 on t2.Table1ID = t1.id
Either GROUP BY or WHERE clause that filters on the most recent:
SELECT * FROM Table1 a
INNER JOIN Table2 b ON (a.id = b.Table1ID)
WHERE NOT EXISTS(
SELECT 1 FROM Table2 c WHERE c.Table1ID = a.id AND c.BatchID > b. BatchID
)

Resources