Combining two queries (MS SQL) - sql-server

I have two tables
One table connects "client ID" with "product id"
TABLE A
ClientID ProductID
1 2
1 4
1 6
2 3
2 5
Then there is another table that logs the amount of time spent with a product:
TABLE B
ProductID Time Date_added
2 10 (datetime)
4 2 (datetime)
2 3 (datetime)
4 1 (datetime)
How do I combine two queries:
One query to get all the product id's associated with a client
SELECT ProductID FROM TABLE_A where ClientID = 1
Then get a monthly sum of all the time spent with those products?
SELECT SUM(time) from Table_B WHERE DATEPART(month, Date_added) = 8 AND ProductID = (products from the previous query?)

Sounds like you want a join statement, taking a shot in the dark but probably
SELECT A.ClientID,SUM(B.Time)
FROM
TABLE A AS A
LEFT JOIN
TABLE B AS B ON (A.ProductID = B.ProductID)
WHERE
DATEPART(month, B.Date_added) = 8
GROUP BY
A.ClientID
This will show the total of time for all products as grouped by the Client ID. This will also include clients that did not have any time spent on products for the month

You're really very close.
SELECT SUM(B.time)
FROM Table_B B INNER JOIN
Table_A A ON B.ProductID = A.ProductID
WHERE DATEPART(month, B.Date_added) = 8
AND A.ClientID = 1
;

SELECT SUM(time) from Table_B
WHERE DATEPART(month, Date_added) = 8
AND ProductID IN (SELECT ProductID FROM TABLE_A where ClientID = 1)
Updated to use IN instead of =

SELECT SUM(time)
FROM B
Join A on A.productID = B.ProductID
WHERE where a.clientID =1
group my month(b.date);

Related

Return sum using aggregate function in SQL Server

I have two tables.
Table1 has following data
Id1 Name Comments
--------------------
1 abc hgdhg
2 xyz mnoph
3 ysdfr jkljk
4 asdf iiuoo
5 pqrs liuoo
Table2 has following data
Id2 Id1 count date
-------------------------------
1 1 18 11/16/2005
2 1 1 11/15/2005
3 1 4 11/25/2005
4 2 4 11/22/2005
5 3 8 11/05/2005
6 3 3 11/30/2005
7 4 2 11/29/2005
8 3 0 11/04/2005
9 2 5 11/02/2005
10 3 9 11/22/2005
11 2 15 11/10/2005
12 5 12 11/19/2005
I want to return output as name, comments, sum of all count since 11/10/2005
I am trying the following query(with out date where condition)
select
Name, Comments, sum(count)
from
Table1 T1
join
Table2 T2 on T1.Id1 = T2.Id1
group by
ID1
But it is throwing error
Name is invalid in the select list because it is not contained in either an aggregate function or the Group by clause.
Can anyone help me with query (with the date where condition)? What's wrong with this?
Thanks in advance
You have to add any columns not contained in the aggregate function, and use where to filter the results:
select Name,
Comments,
sum(count)
from Table1 T1 join Table2 T2 on T1.Id1 = T2.Id1
where T2.[date] >= '11/10/2005'
group by Name, Comments
you can use below query
SELECT T1.Name ,
T1.Comments ,
SUM(T2.[count]) AS [count]
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.Id1 = T2.Id1
WHERE CAST(T2.[date] AS DATE) >= CAST('11/10/2005' AS DATE)
GROUP BY T1.Name ,
T1.Comments
Every column in a select statement without an aggregate function needs to be in the group by sentence too to prevent aggregate errors, about limiting the date, use where clause to define the condition, like shows ahead.
select
Name, Comments, sum(count)
from
Table1 T1
join
Table2 T2 on T1.Id1 = T2.Id1
where
date >= '2005-11-10 00:00:00'
group by
Name, Comments

MS SQL Server - Join two tables where ID is equivalent to new 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

SQL SERVER MULTIPLE JOIN: avoid duplicate values

I have 3 tables in my db:-
Customer:
CId | CName | CLocation | CJoinDate
Payment:
TxnId | TxStatus | TxComment | TxAmount | CId | TxDate
Appointment:
AppId | AppCode | CId | ADate | AComment
When I do a Left join with two tables then the calculated results come right. But when I try to do join with 3 tables then the result calculated is wrong.
for eg:-
If I try this query then the total amount calculated is correct:
SELECT c.CName, sum(p.TxAmount)
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
In the above query I am just joining two tables which gives me the correct result.
Now when I want to show all the records in one table so I had to join 3 tables.
Below is the query I tried:
SELECT c.CName as Name, sum(p.TxAmount) as Payment, count(distinct a.ADate) as Total_Visit
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId LEFT JOIN Appointment a ON c.CId = a.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
The above query gives me wrong Payment amount for each customers. The reason for the wrong result is the Appointments table has more rows as compared to Payment table for each customer. So to show all the appointment entries, the payment amount gets duplicated coz of which the calculation gets wrong.
How can I fix the above scenario witht the above query.
Tks
EDIT: Actually theres 2-3 more tables which I have to join similiar to Appointment table along with a GROUP BY clause for each month.
EDIT1: Fixed it by multiple CTE. Thanks for your valuable pointers it was indeed helpful.
Use a simple CTE expression if you are sure that your sum is calculated correctly by the first query
WITH cte AS
(
SELECT c.CName, c.CID, sum(p.TxAmount) AS sumAmount
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName, c.CID
)
SELECT cte.CName, cte.sumAmount, count(distinct a.ADate) as Total_Visit
FROM cte LEFT JOIN Appointment a ON c.CId = a.CId
GROUP BY c.CName, cte.sumAmount
Try to use a sub query:
SELECT
c.CName as Name
, sum(p.TxAmount) as Payment
, Total_Visit = (SELECT count(distinct a.ADate) FROM Appointment a ON c.CId = a.CId)
FROM Customer c
LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
You can calculate total_visit per CId and then join the subquery
SELECT
c.CName as Name
, sum(p.TxAmount) as Payment
, Total_Visit
FROM Customer c
LEFT JOIN Payment p ON c.CId = p.CId
LEFT JOIN (SELECT a.CId, count(distinct a.ADate) Total_visit FROM Appointment a group by a.CId) as a on c.CId = a.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;

SQL Server - Select most recent records with condition

I have a table like this.
Table :
ID EnrollDate ExitDate
1 4/1/16 8/30/16
2 1/1/16 null
2 1/1/16 7/3/16
3 2/1/16 8/1/16
3 2/1/16 9/1/16
4 1/1/16 12/12/16
4 1/1/16 12/12/16
4 1/1/16 12/12/16
4 1/1/16 null
5 5/1/16 11/12/16
5 5/1/16 11/12/16
5 5/1/16 11/12/16
Need to select the most recent records with these conditions.
One and only one record has the most recent enroll date - select that
Two or more share same most recent enroll date and one and only one record has either a NULL Exit Date or the most recent Exit Date - Select the record with null. If no null record pick the record with recent exit date
Two or more with same enroll and Exit Date - If this case exists, don't select those record
So the expected result for the above table should be :
ID EnrollDate ExitDate
1 4/1/16 8/30/16
2 1/1/16 null
3 2/1/16 9/1/16
4 1/1/16 null
I wrote the query with group by. I am not sure how to select with the conditions 2 and 3.
select t1.* from table t1
INNER JOIN(SELECT Id,MAX(EnrollDate) maxentrydate
FROM table
GROUP BY Id)t2 ON EnrollDate = t2.maxentrydate and t1.Id=t2.Id
Please let me know what is the best way to do this.
Using the rank() window function, I think it's possible.
This is untested, but it should work:
select t.ID, t.EnrollDate, t.ExitDate
from (select t.*,
rank() over(
partition by ID
order by EnrollDate desc,
case when ExitDate is null then 1 else 2 end,
ExitDate desc) as rnk
from tbl t) t
where t.rnk = 1
group by t.ID, t.EnrollDate, t.ExitDate
having count(*) = 1
The basic idea is that the rank() window function will rank the most "recent" rows with a value of 1, which we filter on in the outer query's where clause.
If more than one row have the same "most recent" data, they will all share the same rank of 1, but will get filtered out by the having count(*) = 1 clause.
Use ROW_NUMBER coupled with CASE expression to achieve the desired result:
WITH Cte AS(
SELECT t.*,
ROW_NUMBER() OVER(
PARTITION BY t.ID
ORDER BY
t.EnrollDate DESC,
CASE WHEN t.ExitDate IS NULL THEN 0 ELSE 1 END,
t.ExitDate DESC
) AS rn
FROM Tbl t
INNER JOIN (
SELECT
ID,
COUNT(DISTINCT CHECKSUM(EnrollDate, ExitDate)) AS DistinctCnt, -- Count distinct combination of EnrollDate and ExitDate per ID
COUNT(*) AS RowCnt -- Count number of rows per ID
FROM Tbl
GROUP BY ID
) a
ON t.ID = a.ID
WHERE
(a.DistinctCnt = 1 AND a.RowCnt = 1)
OR a.DistinctCnt > 1
)
SELECT
ID, EnrollDate, ExitDate
FROM Cte c
WHERE Rn = 1
The ORDER BY clause in the ROW_NUMBER takes care of conditions 2 and 3.
The INNER JOIN and the WHERE clause take care of 1 and 4.
ONLINE DEMO
with B as (
select id, enrolldate ,
exitdate,
row_number() over (partition by id order by enrolldate desc, case when exitdate is null then 0 else 1 end, exitdate desc) rn
from ab )
select b1.id, b1.enrolldate, b1.exitdate from b b1
left join b b2
on b1.rn = b2.rn -1 and
b1.id = b2.id and
b1.exitdate = b2.exitdate and
b1.enrolldate = b2.enrolldate
where b1.rn = 1 and
b2.id is nULL
The left join is used to fullfill the 3) requirement. When record is returned then we don't want it.

How to Select distinct data from three tables?

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

Resources