Left Outer Join SSMS - sql

I am attempting to left outer join between two tables.
select id, startdate, name, code, email from edw.dbo.starts
id startdate name code email yearfiled
15 2/4/2018 SO 1083 sql#gmail.com 2018
17 3/4/2018 SO 1083 ssms#gmail.com 2018
19 4/4/2018 SO 1083 ssrs#gmail.com 2018
21 5/4/2018 SO 1083 ssas#gmail.com 2018
21 5/5/2017 SO 1083 who#gmail.com 2017
select customer, return_year, revenue, code from sql.dbo.paid
customer return_year revenue code
15 2018 15.00 1083
17 2018 25.00 1083
21 2018 35.00 1083
21 2017 35.00 1083
select
month(os.startdate) as startmonth
,os.name
,os.code
,coalesce(s.revenue, 0) as revenue
,count(os.email) as commission
from
edw.dbo.starts as os
left outer join
sql.dbo.paid as s
on
os.id = s.customer
and os.yearfile = s.return_year
where
os.yearfiled = 2018
and os.code = '1083'
and os.startdate is not null
group by
month(os.startdate)
,os.name
,os.code
,coalesce(s.revenue, 0);
startmonth name code revenue commission
2 SO 1083 15.00 1
3 SO 1083 25.00 1
4 SO 1083 0.00 1
5 SO 1083 0.00 1
The issue:
Customer = 21 from sql.dbo.paid shows zero for the revenue in the joined query even though it had a reported $35.00 revenue in the table.
Requested:
startmonth name code revenue commission
2 SO 1083 15.00 1
3 SO 1083 25.00 1
4 SO 1083 0.00 1
5 SO 1083 35.00 1

Please try this one.
create table starts
(id int ,
startdate date ,
name varchar(10),
code int ,
email varchar(20),
yearfiled int )
create table paid
( customer int ,
return_year int ,
revenue decimal(10,2),
code int)
insert into starts values
(15,'2/4/2018','SO',1083,'sql#gmail.com',2018),
(17,'3/4/2018','SO',1083,'ssms#gmail.com',2018),
(19,'4/4/2018','SO',1083,'ssrs#gmail.com',2018),
(21,'5/4/2018','SO',1083,'ssas#gmail.com',2018),
(21,'5/5/2017','SO',1083,'who#gmail.com',2017)
insert into paid values
(15,2018,15.00,1083),
(17,2018,25.00,1083),
(21,2018,35.00,1083),
(21,2017,35.00,1083)
select month(a.startdate)as startmonth,a.name,a.code,
case when b.revenue is null then 0 else b.revenue end as revenue,
count(a.email) as commission
from starts a
left join paid b on a.yearfiled=b.return_year and a.id=b.customer
where a.yearfiled=2018 and a.code=1083
group by month(a.startdate),a.name,a.code,b.revenue
/*
startmonth name code revenue commission
----------- ---------- ----------- --------------------------------------- -----------
2 SO 1083 15.00 1
3 SO 1083 25.00 1
4 SO 1083 0.00 1
5 SO 1083 35.00 1
*/

Related

How to get top values when there is a tie

I am having difficulty figuring out this dang problem. From the data and queries I have given below I am trying to see the email address that has rented the most movies during the month of September.
There are only 4 relevant tables in my database and they have been anonymized and shortened:
Table "cust":
cust_id
f_name
l_name
email
1
Jack
Daniels
jack.daniels#google.com
2
Jose
Quervo
jose.quervo#yahoo.com
5
Jim
Beam
jim.beam#protonmail.com
Table "rent"
inv_id
cust_id
rent_date
10
1
9/1/2022 10:29
11
1
9/2/2022 18:16
12
1
9/2/2022 18:17
13
1
9/17/2022 17:34
14
1
9/19/2022 6:32
15
1
9/19/2022 6:33
16
3
9/1/2022 18:45
17
3
9/1/2022 18:46
18
3
9/2/2022 18:45
19
3
9/2/2022 18:46
20
3
9/17/2022 18:32
21
3
9/19/2022 22:12
10
2
9/19/2022 11:43
11
2
9/19/2022 11:42
Table "inv"
mov_id
inv_id
22
10
23
11
24
12
25
13
26
14
27
15
28
16
29
17
30
18
31
19
31
20
32
21
Table "mov":
mov_id
titl
rate
22
Anaconda
3.99
23
Exorcist
1.99
24
Philadelphia
3.99
25
Quest
1.99
26
Sweden
1.99
27
Speed
1.99
28
Nemo
1.99
29
Zoolander
5.99
30
Truman
5.99
31
Patient
1.99
32
Racer
3.99
and here is my current query progress:
SELECT cust.email,
COUNT(DISTINCT inv.mov_id) AS "Rented_Count"
FROM cust
JOIN rent ON rent.cust_id = cust.cust_id
JOIN inv ON inv.inv_id = rent.inv_id
JOIN mov ON mov.mov_id = inv.mov_id
WHERE rent.rent_date BETWEEN '2022-09-01' AND '2022-09-31'
GROUP BY cust.email
ORDER BY "Rented_Count" DESC;
and here is what it outputs:
email
Rented_Count
jack.daniels#google.com
6
jim.beam#protonmail.com
6
jose.quervo#yahoo.com
2
and what I want it to be outputting:
email
jack.daniels#google.com
jim.beam#protonmail.com
From the results I am actually getting I have a tie for first place (Jim and Jack) and that is fine but I would like it to list both tieing email addresses not just Jack's so you cant do anything with rows or max I don't think.
I think it must have something to do with dense_rank but I don't know how to use that specifically in this scenario with the count and Group By?
Your creativity and help would be appreciated.
You're missing the FETCH FIRST ROWS WITH TIES clause. It will work together with the ORDER BY clause to get you the highest values (FIRST ROWS), including ties (WITH TIES).
SELECT cust.email
FROM cust
INNER JOIN rent
ON rent.cust_id = cust.cust_id
INNER JOIN inv
ON inv.inv_id = rent.inv_id
INNER JOIN mov
ON mov.mov_id = inv.mov_id
WHERE rent.rent_date BETWEEN '2022-09-01' AND '2022-09-31'
GROUP BY cust.email
ORDER BY COUNT(DISTINCT inv.mov_id) DESC
FETCH FIRST 1 ROWS WITH TIES

PostgreSQL query not fetching correct result for the conditional comparison of aggregate function

I have a products table with following values with id as INT and profit as numeric data type
id profit
1 6.00
2 3.00
3 2.00
4 3.00
5 2.00
6 8.00
7 4.00
8 3.00
9 1.00
10 4.00
11 10.00
12 3.00
13 6.00
14 5.00
15 2.00
16 7.00
17 6.00
18 5.00
19 2.00
20 16.00
21 3.00
22 6.00
23 5.00
24 5.00
25 1.00
26 4.00
27 1.00
28 7.00
29 11.00
30 2.00
31 1.00
32 3.00
33 2.00
34 5.00
35 4.00
I want to fetch id's which have profit more than average profit
My QUERY:
SELECT product_id,profit
FROM products
GROUP BY product_id,profit
HAVING profit > AVG(profit)::INT
But, the above query return's empty result.
when you execute the group by query, the records are grouped based on the parameters and then where/having clauses are applied.
so first group is student id 1 and further grouped by profit 6.00 making its average as 6.00 and with having condition profit >avg(profit), there are no records which match the criteria.
same for all other records. that is why you get empty result set as no number can be > itself.
based on your description though, it can be achieved by multiple selects.
select * from products where profit >(select avg(profit) from products)

SQL get latest record for each ID

I have three tables that contains data as below:
Users
Id Name Other_Columns
---------------------------
1 John Blah
2 Ricky Blah
3 Stella Blah
4 Bob Blah
Saldo
Id User_id Saldo
--------------------
1 3 0.00
2 1 9.00
3 2 0.15
4 4 3.50
Payments
Id User_id Amount Paid_date
------------------------------------------
1 2 10.00 2014-09-01 08:10
2 2 25.00 2014-09-01 09:00
3 3 100.00 2014-05-10 12:47
4 1 20.50 2014-02-23 15:30
How to get result like this:
Id Name Saldo Last Payment
------------------------------------------
1 John 9.00 23.02.2014 20.50
2 Ricky 0.15 01.09.2014 25.00
3 Stella 0.00 0000-00-00 0.00
4 Bob 3.50 10.05.2014 100.00
Thank you.
select u.id, u.name, s.saldo, p.last_paid_date, p2.amount
from users u
join saldo s
on u.id = s.user_id
join (select user_id, max(paid_date) as last_paid_date
from payments
group by user_id) p
on u.id = p.user_id
join payments p2
on p.last_paid_date = p2.paid_date
and p.user_id = p2.user_id
This answer assumes:
(1) On table SALDO, there is one row per USER_ID
(2) On table PAYMENTS, there can be multiple rows per USER_ID
(I'm pretty confident about #2 being true, I don't know about #1, as you didn't say and your sample data doesn't indicate one way or the other)

sql Query on effective date

I would like to get report for drink purchased in whole month but price of the drink can change any time in month and I would like to get report for a month with price change
I have two tables
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
[DrinkHistory]:
ID DrinkID UserID qty DateTaken
----------------------------------------------------------------------
1 1 1 1 2014-05-10
2 1 1 2 2014-05-15
3 2 1 1 2014-06-01
4 2 1 4 2014-06-01
5 1 1 3 2014-05-20
6 1 1 4 2014-05-30
[DrinkPricesEffect]:
PriceID DrinkID DrinkPrice PriceEffectiveDate IsCurrent
-----------------------------------------------------------------------------------
1 1 10.00 2014-05-01 1
2 1 20.00 2014-05-20 1
3 2 9.00 2014-06-01 1
4 2 8.00 2014-01-01 1
5 1 30.00 2014-05-25 1
6 1 40.00 2014-05-28 1
I would like to have result as under date taken between 2014-05-1 to 2014-05-31
DrinkId Qty Price DateTaken PriceEffectiveDate
-----------------------------------------------------------------------
1 1 10 2014-05-10 2014-05-01
1 2 10 2014-05-15 2014-05-01
1 3 20 2014-05-20 2014-05-20
1 4 40 2014-05-30 2014-05-28
Is there any who can give me some idea or write query for me?
If your drink price can change any time in a month you could additionaly save the price for each purchase. I would add a column [PricePaid] to the table [DrinkHistory].
When adding a record to [DrinkHistory], the price for the drink at the moment is known, but later it might change so you save the current price to the history...
Then for your result you could just display the Whole [DrinkHistory]
SELECT * FROM DrinkHistory;
This should work:
Select
DH.DrinkId,
DH.Qty,
DPE.DrinkPrice AS Price,
DH.DateTaken,
DPE.PriceEffectiveDate
FROM DrinkHistory DH
JOIN DrinkPricesEffect DPE ON DPE.PriceID =
(
Select Top 1 PriceID FROM
(
Select PriceID,RANK() OVER(ORDER BY PriceEffectiveDate DESC ) AS rnk
FROM DrinkPricesEffect
WHERE DH.DrinkId = DrinkId AND
DH.DateTaken >= PriceEffectiveDate
)SubQ WHERE rnk = 1
)
WHERE DH.DateTaken Between '2014-05-01' AND '2014-05-30'
Here you can find the SQL Fiddle link: http://sqlfiddle.com/#!6/5f8fb/26/0

I need to show the monthly inventory data

I have a table some thing like as follows for Inventory details.
InventoryTable.
InventoryTableID DateCreated quantity ItemName
-------------------------------------------------
1 2010-02-04 12 abc
2 2010-03-10 4 abc
3 2010-03-13 5 xyz
4 2010-03-13 19 def
5 2010-03-17 15 abc
6 2010-03-29 15 abc
7 2010-04-01 22 xyz
8 2010-04-13 5 abc
9 2010-04-15 6 def
from the above table if my admin wants to know the inventory details for month April 2010 (i.e. Apr 1st 2010 - Apr 30th 2010)
I need the output as shown below.
inventory as on Apr 1st 2010
ItemName Datecreated qty
----------------------------
abc 2010-03-29 15
xyz 2010-04-01 22
def 2010-03-13 19
inventory as on Apr 30th 2010
ItemName Datecreated qty
---------------------------
abc 2010-04-13 5
xyz 2010-04-01 22
def 2010-04-15 6
For your first result set, run with #YourDataParam = '2010-04-01'. For the second set, use '2010-04-30'.
;with cteMaxDate as (
select it.ItemName, max(it.DateCreated) as MaxDate
from InventoryTable it
where it.DateCreated <= #YourDataParam
group by it.ItemName
)
select it.ItemName, it.DateCreated, it.qty
from cteMaxDate c
inner join InventoryTable it
on c.ItemName = it.ItemName
and c.MaxDate = it.DateCreated