Creating table in SQL - sql

Could I get some help creating this query please?
Users book product video slots to advertise ONE product video. The booking table captures these bookings. Booking spots are allocated to a user not to a product or video.
The #1-ranked video for the user's #1-ranked product will be the one that is advertised.
Bookings table
id user_id position
---- ----- --------
1 100 1
2 150 2
Users table
Users can have 1-n bookings
id name
---- ----
100 John Smith
150 Herby Brown
Products table
A user can have 1-n products
id name user_id rank
--- ---- ------- ----
1 bike 100 1
2 stereo 100 2
3 computer 100 3
4 notebook 150 1
5 scooter 150 2
Videos table
A product can have 1-n videos
id name product_id user_id rank
--- ---- ----------- ------- ----
1 bike video1 1 100 1
2 bike video2 1 100 2
3 computer video 3 100 3
4 notebook video 4 150 1
5 scooter video 5 150 2
So, the query reads, in words:
For each booking record, get the #1 ranked video for the #1-ranked product for the booked user. Order the results by booking position.

SELECT v.id,
v.name,
v.rank,
v.user_id,
u.name AS uname
FROM videos v
JOIN users u
ON u.id = v.user_id
JOIN bookings b
ON u.id = b.user_id
WHERE v.product_id = (SELECT id
FROM products
WHERE user_id = b.user_id
ORDER BY rank ASC
LIMIT 1)
ORDER BY b.position ASC, v.rank ASC
some simplified query:
SELECT v.id,
v.name,
v.user_id,
u.name AS uname,
p.name AS pname
FROM videos v
JOIN users u
ON u.id = v.user_id
JOIN bookings b
ON u.id = b.user_id
JOIN products p
ON p.id = v.product_id
WHERE v.product_id = (SELECT id
FROM products
WHERE user_id = b.user_id
AND rank = 1)
AND v.rank = 1
ORDER BY b.position ASC

Related

MSSQL: GROUP BY and Count

I have 3 tables that contain info about users. I would like to find how many of each type of item in each bucket a person has.
I'm not grasping why this wouldn't work. Does table join order matter or something I not aware of?
A sample of the tables:
PERSONS
ID
NAME
1
John
2
Jane
BUCKETS
ID
LABEL
PERSONID
1
Random
1
2
Vacation
1
THINGS
ID
BUCKETID
TYPE
VALUE
1
1
Image
abc12
2
1
Image
abc13
3
1
Video
abc34
4
1
Image
def12
5
1
Video
def34
SELECT P.NAME, B.LABEL, T.TYPE, COUNT(T.TYPE)
FROM PERSONS P
LEFT JOIN BUCKETS B ON
B.PERSONID = P.ID
LEFT JOIN THING T ON
T.BUCKETID = B.ID
GROUP BY P.NAME, B.LABEL, T.TYPE
I expect it to return:
John, Random, Images, 3
John, Random, Videos, 2
But it returns:
John, Random, Images, 5
John, Random, Videos, 5
I have tried COUNT(*) which results in the same and COUNT(DISTINCT T.TYPE) which of course returns 1 as the count.
This works perfectly in MySQL. Fiddle here: https://www.db-fiddle.com/f/vcb3wiPMSAFBXrWbgYxuMH/8
MSSQL is a different beast all together.
I think you want count(distinct) of some sort. I would speculate:
SELECT P.NAME, B.LABEL, T.TYPE, COUNT(DISTINCT T.BUCKETID)
FROM PERSONS P LEFT JOIN
BUCKETS B
ON B.PERSONID = P.ID LEFT JOIN
THING T
ON T.BUCKETID = B.ID
GROUP BY P.NAME, B.LABEL, T.TYPE;

PostgreSQL - Selecting count of unique values in one and two columns

Firstly, I'd like to apologise for the ambiguous title (I promise to revise it once I'm actually aware of the problem I'm trying to solve!)
I have two tables, player and match, which look like the following:
player:
id name
-- ----
1 John
2 James
3 April
4 Jane
5 Katherine
match:
id winner loser
-- ------ -----
1 1 2
2 3 4
Records in the match table represent a match between two players, where the id column is generated by the database, and the values in the winner and loser columns reference the id column in the player table.
I want to run a query which spits out the following:
player.id player.name total_wins total_matches
--------- ----------- ---------- -------------
1 John 1 1
2 James 0 1
3 April 1 1
4 Jane 0 1
5 Katherine 0 0
I currently have a query which retrieves total_wins, but I'm not sure how to get the total_matches count on top of that.
select p.id, p.name, count(m.winner)
from player p left join match m on p.id = m.winner
group by p.id, p.name;
Thanks for your help!
Try
select p.id, p.name,
sum(case when m.winner = p.id then 1 end ) as total_wins,
count(m.id) as total_matches
from player p
left join match m on p.id in ( m.winner, m.loser )
group by p.id, p.name;
One method splits the match match table, so you have a single row for each win and loss. The rest is just a left join and aggregation:
select p.id, p.name, coalesce(sum(win), 0) as win, count(m.id) as total_matches
from player p left join
(select match, winner as id, 1 as win, 0 as loss from match
union all
select match, loser as id, 0 as win, 1 as loss from match
) m
on p.id = m.id
group by p.id, p.name;

Group by with two columns

I am trying to write a query using group by in sub query ,I referred lot of blogs but could not get all the values.
I have three tables and below is the structure of those tables.
Pet_Seller_Master
ps_id ps_name city_id
2 abc 1
3 xyz 2
4 fer 4
5 bbb 1
City_Master
city_id city_name
1 Bangalore
2 COIMBATORE
4 MYSORE
Api_Entry
api_id ps_id otp
1 2 yes
2 3
3 2 yes
4 3 yes
5 4
6 5 yes
7 5 yes
8 5 yes
Query is to get number of sellers, no of pet sellers with zero otp, no of pet sellers with 1 otp, no of pet sellers with 2 otp,no of pet sellers with otp>2 for the particular city and within date range.
Through Below query I am able to get city , psp , and zero otp
select cm.city_name,
count(ps.ps_id) as PSP,
((select count(ps1.ps_id)
FROM ps_master ps1
WHERE ps1.city = cm.city_id)-
(SELECT count(distinct ps1.ps_id)
from ps_master ps1
INNER JOIN api_entry ae ON ps1.ps_id = ae.ps_id and otp!=''
WHERE ps1.city = cm.city_id and date(timestamp) >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY AND date(timestamp) < curdate())) as zero_psp
from ps_master ps INNER JOIN city_master cm ON ps.city = cm.city_id and cm.city_type = 'IN HOUSE PNS'
group by city_id
Please tell me the solution to solve this query.
Thanks in advance
It's not hard to do and you were on a right track. Here is what I would use:
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from Api_Entry a
inner join Pet_Seller_Master p on p.ps_id=a.ps_id
inner join City_Master c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
Now, if you want to get the number of sellers with zero otp, you just apply where clause:
where otp <> 'yes'
If you want to get the number of pet sellers with otp>2, then you just use subquery:
select *
from (
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from #tempA a
inner join #tempP p on p.ps_id=a.ps_id
inner join #tempC c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
) g
where nbr > 2

fetch parent category name if searching word is found subcategory of category master

i want to fetch parentcategory name.
SELECT u.id,u.fullname,u.email,u.ServiceDescription,
u.Skills,c.Name,r.Reviews,r.RatingValue,ru.Id,
ru.Fullname FROM UserDetails u
INNER JOIN VendorInCategory v ON v.VendorId=u.Id
INNER JOIN CategoryMaster c ON v.CategoryId=c.Id
left join Review r
on r.VendorId = u.id
left JOIN UserDetails ru ON r.CustomerId = ru.id
WHERE ((u.ServiceDescription LIKE '%Plaster%') OR (u.Skills LIKE '%Plaster%') OR
(c.Name LIKE '%Plaster%'))
ORDER BY ISNULL(r.RatingValue, 0) DESC;
now as you can see from below link my database design:
calculate average rating in sql server
here you can see plaster is subcategory of Construction(Id:40)
so i want to fetch parentcategory if any word i am searching for is found in categorymaster.
if word is found in subcategory then fetch its parentcategory name else fetch parentcategory name only.
can anybody please edit my query to achieve this functionality???
UserDetails:
id Name Servicedescription Skills
1 john Plaster plaster
2 abc construction construction
3 xyz plaster plaster
4 pqr null null(not vendor)
5 lmn null null(not vendor)
Review
id CustomerId Vendorid rating reviews
1 4 1 3 fdd
2 5 1 3 dfg
Now if i am seraching for "Plaster"
then output should be:
VendorId ServiceDescription Skills rating customername reviews ParentCategory
1 plaster plaster 3 pqr fdd construction
3 plaster plaster 3 lmn dfg Construction
here Construction(Id 40) is the ParentCategory of Plaster(Id 44) as u can see in image.if plaster does not have parentid then ParentCategory name should be plaster only.
Try this..
SELECT u.id,u.fullname,u.email,u.ServiceDescription,
u.Skills,c.Name,r.Reviews,r.RatingValue,ru.Id,
ru.Fullname,ISNULL(c1.Name,c.Name) AS CategoryName FROM UserDetails u
INNER JOIN VendorInCategory v ON v.VendorId=u.Id
INNER JOIN CategoryMaster c ON v.CategoryId=c.Id
LEFT JOIN CategoryMaster c1 ON c1.Id=c.ParentID
left join Review r
on r.VendorId = u.id
left JOIN UserDetails ru ON r.CustomerId = ru.id
WHERE ((u.ServiceDescription LIKE '%Plaster%') OR (u.Skills LIKE '%Plaster%') OR
(c.Name LIKE '%Plaster%'))
ORDER BY ISNULL(r.RatingValue, 0) DESC;
The below query will give parent:
SELECT c.Name AS Name,c1.Name As Parent FROM CategoryMaster c
LEFT JOIN CategoryMaster c1 on c1.ParentID=c.ID
Use Common table expression (CTE)
Recursive CTE calls
Sample User table structure
userId userName managerId
----------- ---------------- -----------
1 John NULL
2 Charles 1
3 Nicolas 2
4 Neil 5
5 Lynn 1
6 Vince 5
7 Claire 6
In order to get all top level managers name we need to use CTE recursive call.
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u;
The above query will return all the managers name of userid = 7. Below is the output
userId userName managerId steps
----------- ---------------- ----------- -----------
7 Claire 6 0
6 Vince 5 1
5 Lynn 1 2
1 John NULL 3

SQL: Select from many-many through, joined on conditions in through table

Can't get my head around this...
I have 3 tables like this:
Computers
---------
Id
Name
ComputerLogins
--------------
Computer_Id
User_Id
NumberOfLogins
Users
-----
Id
Name
Computers "have and belong to many" Users "through" ComputerLogins.
Sample data:
Computers: Id Name
1 "Alpha"
2 "Beta"
3 "Gamma"
Users: Id Name
1 "Joe"
2 "Fred"
ComputerLogins: Computer_Id User_Id NumberOfLogins
1 1 5
1 2 12
2 1 10
2 2 6
3 1 2
3 2 4
I'm trying to construct a view that will output one row for each record in Computers, and join a Users row through MAX(NumberOfLogins) in ComputerLogins.
Desired output:
Computer_Id User_Id NumberOfLogins
1 2 12
2 1 10
3 2 4
Can you suggest a view query that will produce the desired output?
Thanks!
SELECT
CL.*, U.* --change this as needed
FROM
(
SELECT
Computer_ID, MAX(NumberOfLogins) AS NumberOfLogins
FROM
ComputerLogins
GROUP BY
Computer_ID
) maxC
JOIN
ComputerLogins CL On maxC.Computer_ID = CL.Computer_ID AND maxC.NumberOfLogins = CL.NumberOfLogins
JOIN
Users U On CL.User_ID = U.ID
Wrap in a view etc
Use:
CREATE VIEW your_view AS
SELECT c.id AS computer_id,
u.id AS user_id,
COUNT(*) AS NumberOfLogins
FROM COMPUTERS c
JOIN COMPUTERLOGINS cl ON cl.computer_id = c.id
JOIN USERS u ON u.id = cl.user_id
GROUP BY c.id, u.id