T-SQL query to get desired output - sql-server

I have 2 below tables called T1 and T2
T1 having data as follows
DateList
2021-11-06
2021-11-07
2021-11-08
2021-11-09
T2 having data as follows
EmpId ApplyDate
1 2021-11-07
1 2021-11-09
2 2021-11-09
Now i need t-sql statement that will give date which is not there in T2 for each EmpId.
Output should look as below
DateList EmpId
2021-11-06 1
2021-11-08 1
2021-11-06 2
2021-11-07 2
2021-11-08 2

We can use a cross join between the two tables to generate a reference table containing all date/employee pairs. Then, left anti-join this table to T2 to find all pairs which are not present.
SELECT d.DateList, e.EmpId
FROM T1 d
CROSS JOIN (SELECT DISTINCT EmpId FROM T2) e
LEFT JOIN T2
ON T2.DateList = d.DateList AND
T2.EmpId = e.EmpId
WHERE
T2.DateList IS NULL
ORDER BY
d.DateList,
e.EmpId;

Related

Joining Two Tables, getting Aggregate and unique value of one

This may have been answered previously, but I'm having a difficult time describing my issue.
Let's say I have two tables
Table1
User, CalendarID
Joe 1
Joe 2
Joe 3
Sam 4
Bob 1
Jim 2
Jim 3
Table2
CalendarID, CalendarTime
1 2014-08-18 00:00:00.000
2 2015-01-19 00:00:00.000
3 2015-08-24 00:00:00.000
4 2016-01-18 00:00:00.000
What I would like to do is Join the two tables, only getting a single User Name, and Calendar ID based on what is this highest CalendarTime associated with that CalandarID.
So I would like the query to return
User CalendarID
Joe 3
Sam 4
Bob 1
Jim 3
The closest I've managed is
SELECT t1.User, MAX(t2.CalendarTIme) AS CalendarTime
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
Group By t1.User
Which gets me the User and CalendarTime that I want, but not the Calendar ID, which is what I really want. Please help.
Closest to your script and pretty straightforward:
SELECT t1.User, t2.*
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
WHERE NOT EXISTS
(
SELECT 1 FROM table1 t1_2
INNER JOIN table2 t2_2
ON t2_2.Calendar_ID = t1_2.Calendar_ID
WHERE t1_2.User = t1.User
AND t2_2.CalendarTime > t2.CalendarTime
)
This can be solved for the top N per group:
using top with ties with row_number():
select top 1 with ties
t1.User, t1.CalendarId, t2.CalendarTime
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
order by row_number() over (partition by t1.User order by t2.CalendarTime desc)
or using common table expression(or a derived table/subquery) with row_number()
;with cte as (
select t1.User, t1.CalendarId, t2.CalendarTime
, rn = row_number() over (partition by t1.User order by t2.CalendarTime desc)
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
)
select User, CalendarId, CalendarTime
from cte
where rn = 1

Stored Proc to insert rows using Joins

I have 2 tables having IP_Address as common column. My requirement is to get the IP_Address and its associated details in table 1 that are for last 90 days and are not in table 2 and insert the delta in a new table on an nightly basis
DB used: oracle 11g
Table 3 should contain 1 record per IP_Address from Table 1 that are not in Table 2
Table 1
--------------------------------------------------
IP_Address Store_name source TRANS_INIT_TIME
--------------------------------------------------
192.168.0.1 abc e 16-06-29 05:49:16.775265000
192.168.0.1 abc e 16-07-01 07:44:29.019723000
192.168.0.2 ghi b 16-07-06 10:53:54.588610000
192.168.0.2 ghi b 16-07-12 04:04:20.293644000
192.168.0.3 hjg e 16-07-12 03:54:36.024915000
192.168.0.3 hjg e 16-07-15 03:46:27.712961000
192.168.0.4 uiu e 16-09-12 08:57:48.360136000
Table 2
--------------------------
IP.Address loc name
--------------------------
192.168.0.2 hjh uiui
Table 3
--------------------------------
IP_Address Store_name source
-------------------------------
I have prepared join to get the unique IP_Address from table1.
SELECT DISTINCT T1.IP_ADDRESS
FROM Table1 T1
LEFT JOIN TABLE2 T2
ON T1.IP_ADDRESS= T2.IP_ADDRESS
WHERE T1.TRANS_INIT_TIME BETWEEN SYSDATE-90 AND SYSDATE
AND T2.IP_ADDRESS IS NULL
AND T1.IP_ADDRESS IS NOT NULL;
I am struck here on how to get the first row data for these returns IPs and insert them in table 3 through procedure. can anyone help no this ?
Expected Result:
Table 3
--------------------------------
IP_Address Store_name source
-------------------------------
192.168.0.1 abc e
192.168.0.2 ghi b
192.168.0.3 hjg e
192.168.0.4 uiu e
In your case is enough test only the left join key column that is null (this mean that this key don't match with the key form the main table
and for insert you can use an insert select
INSERT INTO Table3 (IP_ADDRESS, Store_name, source)
SELECT DISTINCT T1.IP_ADDRESS, min(T1.Store_name), min(T1.Source)
FROM Table1 T1
LEFT JOIN TABLE2 T2
ON T1.IP_ADDRESS= T2.IP_ADDRESS
WHERE T1.TRANS_INIT_TIME BETWEEN SYSDATE-90 AND SYSDATE
and AND T2.IP_ADDRESS IS NULL
group by T1.IP_ADDRESS
You want the IP_ADDRESS to be unique in the result set but you haven't indicated which row you want for store_name and source. Just pick one randomly maybe? I'm not sure which one you want but here are three different ways to get that table3 you want.
Using an aggregate so you can group by IP_ADDRESS and correlated subquery:
SELECT T1.IP_ADDRESS, MAX(T1.STORE_NAME) AS STORE_NAME, MAX(T1.SOURCE) AS SOURCE
FROM Table1 T1
WHERE NOT EXISTS (SELECT NULL
FROM TABLE2 T2
WHERE T1.IP_ADDRESS = T2.IP_ADDRESS)
GROUP BY T1.IP_ADDRESS
ORDER BY T1.IP_ADDRESS;
Using an aggregate and a left outer join:
SELECT T1.IP_ADDRESS, MAX(T1.STORE_NAME) AS STORE_NAME, MAX(T1.SOURCE) AS SOURCE
FROM Table1 T1
LEFT OUTER JOIN TABLE2 T2 ON T1.IP_ADDRESS = T2.IP_ADDRESS
WHERE T2.IP_ADDRESS IS NULL
GROUP BY T1.IP_ADDRESS
ORDER BY T1.IP_ADDRESS;
Using an analytical function and correlated subquery:
SELECT SUB.IP_ADDRESS, SUB.STORE_NAME, SUB.SOURCE
FROM (
SELECT T1.IP_ADDRESS, T1.STORE_NAME, T1.SOURCE, ROW_NUMBER() OVER (PARTITION BY T1.IP_ADDRESS) AS ROWNUMBER
FROM Table1 T1
WHERE NOT EXISTS (SELECT NULL
FROM TABLE2 T2
WHERE T1.IP_ADDRESS = T2.IP_ADDRESS)
) AS SUB
WHERE SUB.ROWNUMBER = 1
ORDER BY SUB.IP_ADDRESS;

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

How to get values from two tables in SQL Server?

I have 2 tables in SQL Server 2008 and I want to get the details from those 2 tables using join.
T-1 : vwHardwareConsolidate
|ID|||Qty|Type|Task_Id|
T-2 :
|MasterID|Task_Id|Act_Qty|
I want to get id, task_name, sum(qty), task_id from T1 and Masterid, Act_Qty from T2
I have tried this query
select
ID as MasterID, Task_id, Task_Name as Items,
SUM(Qty) as Req_Qty, 0 as Act_Qty
from
vwHardwareConsolidate
where
type = 'Reqrd' and ID = '21'
Group by
Task_Name,id,Task_id
union
(select
m.MasterID, m.Task_Id, vw.Task_Name as Items, 0 as Req_Qty, m.Act_Qty
from
vwHardwareConsolidate vw
Right join
(select
MasterID, m.Task_Id, 0 as Req_Qty, sum(Act_qty) as Act_Qty
from
tbl_MaterialDistribution_Detail m
where
MasterID = '21'
group by
m.Task_Id, MasterID) as m on m.Task_Id = vw.Task_id)
vwHardwareConsolidate
ID Site_name Qty Task_Name Type
1 CITY 1 A16Port_Switch Reqrd
1 CITY 1 Digital_Camera Reqrd
1 CITY 1 Electronic_Pen Reqrd
tbl_MaterialDistribution_Detail:
MasterID|TaskId|Act_qty
7 31 1
2 32 1
12 39 3
Please try this
select t1.ID, t1.Task_Name,Sum(t1.Qty) as Qty,t1.Task_Id,t2.MasterID,t2.Act_Qty
from vwHardwareConsolidate as t1
left outer join table2 as t2
on t2.Task_ID=t1.Task_ID
Group By t1.ID, t1.Site_name, t1.Task_Name,t1.Qty,t1.Type,t1.Task_Id,t2.MasterID,t2.Act_Qty
May this will help you.
SQL Fiddle Demo
You can use
SELECT T1.Id, T1.SiteName,T1.TaskName,T.Type,T2.Act_Qty,T2.MasterID,T2.Task_Id,SUM(Qty)AS
Qty FROM T1 INNER JOIN T2 ON T1.Task_Id=T2=Task_Id GROUP BY T1.Id, T1.SiteName,
T1.TaskName,T.Type,T2.Act_Qty,T2.MasterID,T2.Task_Id
something this way,
select a.id,a.Task_Name,b.qty,c.Act_Qty from vwHardwareConsolidate a inner join
tbl_MaterialDistribution_Detail c on a.id=c.task_id
inner join
(slect id,sum(qty)qty from vwHardwareConsolidate group by id)b
on a.id=b.id

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

Resources