I was hoping someone could help me.
I have the following 5 tables:
tblCustomer
CustomerID CustomerName
------- ------------
1 ABC Bank
2 Chase Bank
tblOrderType
OrderTypeID OrderTypeName
---------- ------------
1 Assignment
2 LienRelease
tblActivity
ActivityID ActivityName
---------- ------------
1 Received
2 Keyed
3 Printed
4 Delivered To Cusotmer
tblOrder
OrderID CustomerID OrderTypeID LoanNumber
---------- ------------ ----------- ----------
1 1 1 45584565
2 1 1 45566856
3 1 1 45565584
4 1 1 45588545
tblOrderActivity
OrderID ActivityID ActivityDate
---------- ----------- ----------
1 1 2007-04-16 8:34:00 AM
1 2 2007-04-16 9:22:00 AM
1 3 2007-04-16 9:51:00 AM
1 4 2007-04-16 4:14:00 PM
2 1 2007-04-16 8:34:00 AM
3 1 2007-04-16 8:34:00 AM
3 2 2007-04-16 9:22:00 AM
3 3 2007-04-16 9:51:00 AM
3 4 2007-04-16 4:14:00 PM
4 1 2007-04-16 8:34:00 AM
4 2 2007-04-16 9:22:00 AM
4 3 2007-04-16 9:51:00 AM
The information has been changed for protection purposes. So say I need to be able to list all Assignment orders that have a “Received” activity but not a “Delivered” activity for ABC Bank and I need to return CustomerName, CustomerID, LoanNumber, and “received date” (Activity Date for received). I have been able to get everything done, however, I am unable to remove any files that have not had an Activity of "Delivered". Here is what I have so far:
SELECT tblCustomer.CustomerName, tblCustomer.CustomerID, tblOrder.LoanNumber, (tblOrderActivity.ActivityDate) AS [received date]
FROM tblOrderActivity (NOLOCK)
INNER JOIN tblOrder (NOLOCK)
ON tblOrderActivity.OrderID = tblOrder.OrderID
INNER JOIN tblCustomer (NOLOCK)
ON tblOrder.CustomerID = tblCustomer.CustomerID
INNER JOIN tblOrderType (NOLOCK)
ON tblOrder.OrderTypeID = tblOrderType.OrderTypeID
INNER JOIN tblActivity (NOLOCK)
ON tblActivity.ActivityID = tblOrderActivity.ActivityID
WHERE tblOrderType.OrderTypeName = 'Assignment'
AND EXISTS (SELECT DISTINCT [OrderID] FROM [tblOrderActivity] WHERE tblActivity.ActivityName = 'Received')
AND NOT EXISTS (SELECT DISTINCT [OrderID] FROM [tblOrderActivity] WHERE tblActivity.ActivityName = 'Delivered To Customer')
GROUP BY tblCustomer.CustomerName, tblCustomer.CustomerID, tblOrder.LoanNumber, tblOrderActivity.ActivityDate;
And my results are below
CustomerName CustomerID LoanNumber received date
---------- ------------ ----------- ----------
ABC Bank 1 45565584 2007-04-16 08:34:00.000
ABC Bank 1 45566856 2007-04-16 08:34:00.000
ABC Bank 1 45584565 2007-04-16 08:34:00.000
ABC Bank 1 45588545 2007-04-16 08:34:00.000
Try this. Not the most efficient t-sql in the world, but the schema doesn't help much. May need to alias the tables in the main query to make it more readable and ensure the subqueries work properly (at least that's what I usually do).
This should return all received records that do not have a delivery
SELECT tblCustomer.CustomerName, tblCustomer.CustomerID, tblOrder.LoanNumber, (tblOrderActivity.ActivityDate) AS [received date]
FROM tblOrderActivity (NOLOCK)
INNER JOIN tblOrder (NOLOCK)
ON tblOrderActivity.OrderID = tblOrder.OrderID
INNER JOIN tblCustomer (NOLOCK)
ON tblOrder.CustomerID = tblCustomer.CustomerID
INNER JOIN tblOrderType (NOLOCK)
ON tblOrder.OrderTypeID = tblOrderType.OrderTypeID
INNER JOIN tblActivity (NOLOCK)
ON tblActivity.ActivityID = tblOrderActivity.ActivityID
WHERE tblOrderType.OrderTypeName = 'Assignment'
AND NOT EXISTS (SELECT 1 FROM [tblOrderActivity] WHERE OA.ActivityID = 4 AND OA.OrderID = tblOrder.OrderID) --Delivered Excluded
AND tblOrderActivity.ActivityID = 1 --Received Only
Here is how I would do the query
SELECT *
FROM tblOrder
LEFT JOIN (
SELECT 'r' AS r, tblOrderActivity.ActivityDate, tblActivity.ActivityName, tblOrderActivity.OrderID
FROM tblOrderActivity
JOIN tblActivity ON tblOrderActivity.ActivityID = tblActivity.ActivityID
AND tblActivity.ActivityName = 'Received'
) AS Received ON tblOrder.OrderID = Received.OrderID
LEFT JOIN (
SELECT 'd' AS d, tblOrderActivity.ActivityDate, tblActivity.ActivityName, tblOrderActivity.OrderID
FROM tblOrderActivity
JOIN tblActivity ON tblOrderActivity.ActivityID = tblActivity.ActivityID
AND tblActivity.ActivityName = 'Delivered To Cusotmer'
) AS Delivered ON tblOrder.OrderID = Delivered.OrderID
WHERE Delivered.ActivityDate IS NULL
or like this
SELECT *
FROM tblOrder
LEFT JOIN (
SELECT 'r' AS r, tblOrderActivity.ActivityDate, tblActivity.ActivityName, tblOrderActivity.OrderID
FROM tblOrderActivity
JOIN tblActivity ON tblOrderActivity.ActivityID = tblActivity.ActivityID
AND tblActivity.ActivityID IN (SELECT ActivityID FROM tblActivity WHERE tblActivity.ActivityName = 'Received')
) AS Received ON tblOrder.OrderID = Received.OrderID
LEFT JOIN (
SELECT 'd' AS d, tblOrderActivity.ActivityDate, tblActivity.ActivityName, tblOrderActivity.OrderID
FROM tblOrderActivity
JOIN tblActivity ON tblOrderActivity.ActivityID = tblActivity.ActivityID
AND tblActivity.ActivityID IN (SELECT ActivityID FROM tblActivity WHERE tblActivity.ActivityName = 'Delivered To Cusotmer')
) AS Delivered ON tblOrder.OrderID = Delivered.OrderID
WHERE Delivered.ActivityDate IS NULL
trim it down to just the columns you want of course
Related
I have the following tables:
Customers
ID Name
============
1 John
2 Alice
3 Bob
Orders
ID CustomerID Status
==========================
1001 1 1
1002 2 1
1003 2 2
1004 3 2
I'd like to join tables showing one entry per customer only (the one with lowest Status) i.e.
ID Name OrderID
======================
1 John 1001
2 Alice 1002
3 Bob 1004
Thanks to the answer to this question, I chose 2 solutions which produce the same output:
Solution 1
SELECT c.id, c.name, o.id FROM customers AS c
INNER JOIN orders AS o ON
c.id = o.customerid
WHERE o.status = (SELECT MIN(status) FROM orders WHERE customerid = c.id)
Solution 2
SELECT c.id, c.name, o.id FROM customers as c
INNER JOIN orders AS o ON
o.id = (SELECT TOP 1 id FROM orders WHERE customerid = c.id ORDER BY status)
Trying to understand which one runs faster, I used SQL Fiddle View Execution Plan which gave the following:
Solution 1
Solution 2
How to interpret those diagrams and which one performs faster?
Using MS SQL Server 2016.
Here's my breakdown and the last one is my suggestion to you.
Query Cost 67%
SELECT c.id, c.name, o.id FROM #Customers AS c
INNER JOIN #Orders AS o ON
c.id = o.customerid
WHERE o.status = (SELECT MIN(status) FROM #Orders WHERE customerid = c.id)
Query Cost 66%
SELECT c.id, c.name, o.id FROM #Customers as c
INNER JOIN #Orders AS o ON
o.id = (SELECT TOP 1 id FROM #Orders WHERE customerid = c.id ORDER BY status)
Query Cost 47%
SELECT
x.CustID,
x.Name,
x.OrderID
FROM (SELECT
C.id CustID,
c.Name,
o.ID OrderID,
o.status,
ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY o.status) rn
FROM #Customers c
INNER JOIN #Orders o
ON o.CustomerID = c.ID) x
WHERE x.rn = 1
i/p
Id Name InsertBy UpdateBy
1 A 2 2
2 B 1 2
3 C 4 3
4 D 4 5
5 E 1 3
O/P(THE COUNT OF EMPLOYEE ID IN INSERT AND COUNT OF EMPID IN UPDATE)
Name InsertBy UpdateBy
A 2 0
B 1 2
C 0 2
D 2 0
E 0 1
It seems to you would require to do self join with separate query (Inserted, Updated) for safer.
SELECT
t.name, a.insertBy, b.updateBy
FROM table t
INNER JOIN
(
SELECT
t.id, count (t1.insertBy) insertBy
FROM table t
LEFT JOIN table t1 on t1.insertBy = t.id
GROUP BY t.id
)a on a.id = t.id
INNER JOIN
(
SELECT
t.id, count (t2.updateBy) updateBy
FROM table t
LEFT JOIN table t2 on t2.updateBy = t.id
GROUP BY t.id
)b on b.id = t.id
Let me edit with other approach which more efficient with separate join
select t1.name, sum(case when a.Name = 'InsertedBy' then 1 else 0 end) InsertBy,
sum(case when a.Name = 'UpdatedBy' then 1 else 0 end) UpdateBy
from table t
cross apply (
values (InsertBy, 'InsertedBy'), (UpdateBy, 'UpdatedBy')
)a(Types, Name)
LEFT JOIN table t1 on t1.Id = a.Types
group by t1.name
However, these will make use of index on (Id)
I am trying to join two tables but did not able to success
Test Supplier Table
SID NAME
1 Test
2 Test2
Test Stock Table
ID NewID SupID Qty
1 101 1 2
2 102 1 5
3 103 2 6
101 1 4
101 1 7
101 2 5
103 2 10
The output I am looking for
ID NAME Qty
2 Test 5
101 Test 13
101 Test2 5
103 Test2 16
My code is -
Select S.NAME, ST.ID, SUM(ST.Qty)
From Stock ST
Inner Join ST.SupID = S.SID
I need to combine those ID's which are matching with the new ID's with another ID's. If you see the results, I need to combine ID 1 qty with ID 101 because ID 1 has new ID 101 and no need to display ID 1. I have tried inner join but did not work.
First, you find those with NEW ID and those without NEW ID. For those with NewID, use NEWID, for those without use ID (old ID). then you use UNION ALL to combine both result and join to the Supplier table to obtain the NAME.
; with
cte as
(
-- with NewID
select ID = NewID, SupID, Qty = sum(Qty)
from Stock ST
where exists
(
select *
from Stock x
where x.ID = ST.NewID
)
group by NewID, SupID
union all
-- without NewID
select ID, SupID, Qty = sum(Qty)
from Stock ST
where not exists
(
select *
from Stock x
where x.ID = ST.NewID
)
group by ID, SupID
)
select c.ID, SP.NAME, Qty = sum(Qty)
from cte c
inner join Supplier SP on c.SupID = SP.SID
group by c.ID, SP.NAME
Start with the Stock table and join to the Supplier table (remembering to name the table in the join) and then self-left join to the IDs in the Stock table to determine if they exist or not. Then group by on whichever ID you want to keep.
SELECT
COALESCE(ST2.ID, ST.ID) ID
, S.NAME NAME
, SUM(ST.Qty) Qty
FROM Stock ST
INNER JOIN Supplier S
ON ST.SupID = S.SID
LEFT JOIN (
SELECT DISTINCT ID
FROM Stock
) ST2
ON ST.NewID = ST2.ID
GROUP BY
COALESCE(ST2.ID, ST.ID)
, S.NAME
How can I write a SQL statement to select distinct data from three tables?
There are three tables
1)
Registration
id name contact
123 abc 123456789
2) bookingReg
PkBkID FkRegID ac_no
1 123 QT123
3) products
PkPro FkBkID pro_name Qty price
1 1 abc 2 150
2 1 def 1 400
3 1 ghi 5 500
4 1 abc 2 150
SELECT * FROM Registration as a
JOIN bookingReg as b ON (b.FkRegID = '123')
JOIN products as c ON (c.FkBkID = b.PkBkID )
I want distinct pro_name
Out put is
ac_no qty price
QT123 8 1050
HOw ?
Answer based on my assumption
SELECT pro_name,
ac_no,
SUM(qty) Sumqty,
SUM(price) SumPrice
FROM Registration a
JOIN bookingReg b
ON b.FkRegID = a.id
JOIN products c
ON c.FkBkID = b.PkBkID
GROUP BY pro_name, ac_no
EDIT Remove ac_no from SELECT and GROUP BY if you don't want to see this field in result.
Pls try this
SELECT A.ac_no, SUM(A.Qty) Qty, SUM(A.Price) Price
FROM
(
SELECT DISTINCT B.ac_no, P.Qty, P.Price
FROM Registration R
INNER JOIN bookingReg B ON B.FkRegID = R.id
INNER JOIN products P ON P.FkBkID = B.PkBkID
) A
GROUP BY A.ac_no
i have two tables .. one is a master table and other one is an daily report table.
Master table :
machine_id Machinename
1 abc
2 def
3 ghi
4 jkl
ven_fullreportmaster :
entry_date machine_id description_id tot_time shift_id
20110613 1 1 10 1
20110613 2 2 9 2
20110614 1 1 10 1
20110614 1 2 9 2
20110614 3 3 5 3
20110614 2 4 10 1
20110614 2 1 9 2
20110614 2 5 5 3
now, i want to retrieve the data from the daily report table that it should contain all the machine names with tot_time and entry_date..
i have used this query to retrieve the data,
select entry_date,
machinename,
(IsNull(cast(TotalMins / 60 as varchar(24)),'0') + ':' + IsNull(cast(TotalMins % 60 as varchar(24)),'0')) as TotalHrs--, shift_type
from (
select vm.machinename , vfrm.entry_date,
sum(case when vfrm.description_id in ('1','2','3','4','5') then DateDiff(mi, 0, total_time) else '0' end) as TotalMins
--vsm.shift_type
from ven_fullreportmaster vfrm
inner join ven_machinemaster vm on vm.machine_id = vfrm.machine_id
inner join ven_shifttypemaster vsm on vsm.shift_id = vfrm.shift_id
where vfrm.entry_date = '20110614'
-- and vfrm.shift_id in (1,2,3)
group by machinename, vfrm.entry_date --, vsm.shift_type
) as SubQueryALias group by entry_date, machinename,TotalMins --,shift_type
when i run the above query, i am getting details for machine-id 1 , 2,3 alone..
output:
entry_date machineid TotalHrs
2011-06-14 00:00:00.000 1 19:0
2011-06-14 00:00:00.000 2 24:0
2011-06-14 00:00:00.000 3 5:0
i need to get machine_id =4 value as 0 in TotalMins for each shift.. how to resolve it..plz help me ..
expected output:
entry_date machineid TotalHrs
2011-06-14 00:00:00.000 1 19:0
2011-06-14 00:00:00.000 2 24:0
2011-06-14 00:00:00.000 3 5:0
**2011-06-14 00:00:00.000 4 0:0**
thanks and regards
T.Navin
output:
Try using left joins instead of inner joins, that should get machine #3 to appear even though it has no entries in the second table.
You are searching for records with a specific date but there is no entry for 20110614 in your reporting table.
One solution is to add records to your select using a UNION with an initial SUM of'0'.
These fake records will not throw off your existing SUM.
They will show up where there's missing data with '0'.
SQL Statement
SELECT entry_date
, machinename
, (ISNULL(CAST(TotalMins / 60 AS VARCHAR(24)),'0') + ':' + ISNULL(CAST(TotalMins % 60 AS VARCHAR(24)),'0')) AS TotalHrs--, shift_type
FROM (
SELECT vm.machinename
, vfrm.entry_date
, SUM(case when vfrm.description_id in ('1','2','3','4','5') THEN DATEDIFF(mi, 0, total_time) else '0' END) AS TotalMins --vsm.shift_type
FROM ven_fullreportmaster vfrm
INNER JOIN ven_machinemaster vm on vm.machine_id = vfrm.machine_id
INNER JOIN ven_shifttypemaster vsm on vsm.shift_id = vfrm.shift_id
WHERE vfrm.entry_date BETWEEN '20110614' AND '20110615'
GROUP BY
machinename
, vfrm.entry_date --, vsm.shift_type
UNION ALL
SELECT DISTINCT vm.machinename
, vfrm.entry_date
, '0'
FROM ven_machinemaster vm
CROSS APPLY ven_fullreportmaster vfrm
WHERE vfrm.entry_date BETWEEN '20110614' AND '20110615'
) AS SubQueryALias
GROUP BY
entry_date
, machinename
, TotalMins --,shift_type
Instead of:
from ven_fullreportmaster vfrm
inner join ven_machinemaster vm on vm.machine_id = vfrm.machine_id
inner join ven_shifttypemaster vsm on vsm.shift_id = vfrm.shift_id
where vfrm.entry_date = '20110614'
can you try this LEFT JOIN ? Note the moving of the condition from WHERE to the ON clause:
FROM ven_machinemaster vm
LEFT JOIN ven_fullreportmaster vfrm
ON vm.machine_id = vfrm.machine_id
AND vfrm.entry_date = '20110614'
INNER JOIN ven_shifttypemaster vsm
ON vsm.shift_id = vfrm.shift_id
or:
FROM ven_machinemaster vm
LEFT JOIN ven_fullreportmaster vfrm
ON vm.machine_id = vfrm.machine_id
AND vfrm.entry_date = '20110614'
LEFT JOIN ven_shifttypemaster vsm
ON vsm.shift_id = vfrm.shift_id