SQL query to generate the following output - sql

Display user id, user name, total amount, amount to be paid after discount and give alias name as User_ID, user_name, Total_amount, Paid_amount. Display record in descending order by user id. Click on TABLE SHCEMA to get the table
This is the code I've written. But this is not showing the expected result:
SELECT
USERS.USER_ID AS User_ID,
NAME AS user_name,
(FARE * NO_SEATS) AS Total_amount
FROM
USERS
INNER JOIN
TICKETS ON USERS.USER_ID = TICKETS.USER_ID
INNER JOIN
PAYMENTS ON TICKETS.TICKET_ID = PAYMENTS.TICKET_ID
INNER JOIN
DISCOUNTS ON PAYMENTS.DISCOUNT_ID = DISCOUNTS.DISCOUNT_ID
GROUP BY
USERS.USER_ID, NAME, FARE, NO_SEATS
ORDER BY
USERS.USER_ID DESC;
This is the expected output:
USER_ID USER_NAME TOTAL_AMOUNT PAID_AMOUNT
----------------------------------------------
5 Krena 700 625
4 Johan 800 775
3 Ivan 3000 2900
1 John 4000 3950
1 John 4000 3950
1 John 2000 1900

This will work, try it
SELECT
USERS.USER_ID AS USER_ID,
USERS.NAME AS USER_NAME,
(TICKETS.FARE * TICKETS.NO_SEATS) AS TOTAL_AMOUNT,
(TICKETS.FARE * TICKETS.NO_SEATS - DISCOUNTS.DISCOUNT_AMOUNT) AS PAID_AMOUNT
FROM
USERS
INNER JOIN TICKETS
ON USERS.USER_ID=TICKETS.USER_ID
INNER JOIN PAYMENTS
ON TICKETS.TICKET_ID=PAYMENTS.TICKET_ID
INNER JOIN DISCOUNTS
ON PAYMENTS.DISCOUNT_ID=DISCOUNTS.DISCOUNT_ID
ORDER BY USERS.USER_ID DESC;

Try this code.
SELECT
USERS.USER_ID AS USER_ID,
USERS.NAME AS USER_NAME,
(TICKETS.FARE * TICKETS.NO_SEATS) AS TOTAL_AMOUNT,
(TICKETS.FARE * DISCOUNTS.DISCOUNT_AMOUNT) + TICKETS.FARE AS PAID_AMOUNT
FROM
USERS USERS
INNER JOIN TICKETS TICKETS
ON USERS.USER_ID=TICKETS.USER_ID
INNER JOIN PAYMENTS PAYMENTS
ON TICKETS.TICKET_ID=PAYMENTS.TICKET_ID
INNER JOIN DISCOUNTS DISCOUNTS
ON PAYMENTS.DISCOUNT_ID=DISCOUNTS.DISCOUNT_ID
ORDER BY USERS.USER_ID DESC;
I'm confused in your database structure if why is it in number datatype? you might want to change it to decimal if you want and make its length as (11,2) because i assume that your discount amount in your DISCOUNT table is in percentage right? Or just paste your sample database here so i can update my code.

if i had enough reputation, i would have written this as a comment (sigh):
u havent quite defined what ur expected results are.
i assume the following:
print the total sums for a user, both the Total_amount (ie. official price), Paid_amount (ie. after discounts), so it would include all the tickets and their payments.
i assume that the discount is a positive number to be deducted from the fair and is per 1 seat
then this should do the trick:
SELECT
USER_ID AS USER_ID,
NAME AS USER_NAME,
sum(FARE * NO_SEATS) AS TOTAL_AMOUNT,
sum((FARE - DISCOUNT_AMOUNT ) * NO_SEATS) AS PAID_AMOUNT
FROM USERS u
INNER JOIN TICKETS t
ON u.USER_ID=t.USER_ID
INNER JOIN PAYMENTS p
ON t.TICKET_ID=p.TICKET_ID
INNER JOIN DISCOUNTS d
ON p.DISCOUNT_ID=d.DISCOUNT_ID
group by USER_ID, name
ORDER BY USER_ID DESC;

This is the right answer for the question and would give the accurate output
SELECT User_ID, (select name from users u where t.user_id=u.user_id) as
user_name, ticket_id as Ticket_id, (no_seats*fare) as Total_amount,
((no_seats*fare)-(select discount_amount from discounts d
where d.discount_id=(select discount_id from payments p where t.Ticket_id=p.Ticket_id))) as Paid_amount
FROM tickets t ORDER BY User_ID desc;

Write a query to
display user id, user name, ticket id , total amount, amount to be
paid after discount and give alias name as User_ID, user_name,
Ticket_Id, Total_amount, Paid_amount. Display record in descending
order by user id.
Avoid duplicate records.
[Note : Total amount to be paid should be number of tickets * amount per ticket ]
this code runs 100%

Related

Select columns with multiple purcahses in a given date

table structure
I need to get names (FIO) of all the people that purchased product a and product b in any given day (but must be 2 purchases in a day) in april, or any other specified month.
What I tried to do is
with
purchased_items as
(
select customer_key
from purchase p
join product pr
on p.product_key = pr.product_key
where pr.name in ('Teddy bear', 'LEGO')
AND p.date_sold BETWEEN '01.04.2019' AND '30.04.2019'
group by customer_key
having count(distinct p.product_key) = 2
)
select *
from customer c
where exists (
select *
from purchased_items pui
where c.customer_key = pui.customer_key
);
But that only gives clients that bought 2 items in a month (not a single day).
I also suspect that it can be done by querying for Date, Client_name (FIO), array_agg(product.Name /*group by date */ ) , but I am not sure how to implemet it.
Thank you in advance for any help !
EDIT: figured it out.
with a as (
SELECT c.FIO, p.date_sold, pr.Name
FROM customer c
JOIN purchase p ON c.customer_key = p.customer_key
JOIN product pr ON p.product_key = pr.product_key
Where p.date_sold BETWEEN '01.04.2019' AND '30.04.2019' and (pr.name like '%LEGO%' OR pr.name like '%Teddy bear%') ),
count_name as (
select fio, count(distinct Name) as count, date_sold
from a
group by date_sold, fio)
select DISTINCT FIO
from count_name
where count=2
Although it's probably very subotimal

Extracting several math operations outputs from single select query

I have three tables that I need to merge to analyse: active, students and bills.
'Active' contains records on active students and the subjects they have been active on with columns: id (student id) int, time (time they have been active) timestamp, and subject (subject in which were active) - text
id time subject
1 2020-04-23 06:53:30 Math
2 2020-05-13 09:51:22 Physics
2 2020-02-26 17:34:56 History
'Students' is the mass database containing: id (student id) int, group (the group to which student was assigned for a/b test) - text
id group
1 A
2 B
3 A
4 A
'Bills' keeps record of all transactions for courses that student purchased: id (student id) int, sale_time (time when student purchased course) timestamp, subject (subject in which course purchased) text, money (amount paid).
id sale_time subject money
1 2020-03-04 08:54:55 Math 4300
1 2020-04-08 20:43:56 Math 3200
2 2020-05-09 13:43:12 Law 8900
Basically, we have a student database (Students) some of which purchased courses (Bills). While some of those who purchased remain active (Active).
I need to write ONE SINGLE query where I can extract the following grouped by whether they belong to A or B group:
average revenue per user: sum (money) / count (distinct Students.id)
average revenue per active user: sum (money) / count (distinct Active.id)
conversion rate (%): count (distinct Bills.id) / count (distinct Students.id)
conversion rate (active) (%): count (distinct Bills.id) / count (distinct Active.id)
conversion rate (Math) (%) (count (distinct Bills.id) where Bills.subject = Math) / (count (distinct Active.id) where Active.subject = Math)
All these in single query!
I used
select sum (money)/count (distinct Students.id)
from Students
left join Bills using (id)
left join Active using (id)
group by group, Students.id
but I don't know how to do these math calculations all in one right after select with filters.
Please help!
SQL fiddle: https://www.db-fiddle.com/f/NPQR6aBf8H36XvrefJY2J/0
All You need is this:
select s.[group], sum (money)/ NULLIF( count (distinct s.id),0) as
AvgPerUser,
sum (money) / NULLIF(count (distinct a.id),0) as AvgActUser,
count (distinct b.id) / NULLIF(count (distinct a.id),0) as CovRate,
count (distinct b.id) / NULLIF(count (distinct a.id),0) as ConActRate,
(select count(distinct b2.id) from Bills as b2 where b2.subject = 'Math') /
NULLIF((select count ( distinct a2.id) from Active as a2 where a2.subject
='Math'),0) as ConRateMath
from Students as s
left join Bills as b on s.id = b.id
left join Active as a on s.id = a.id
group by s.[group]
I would recommend removing duplicates before joining and then using window functions:
select s.group, avg(b.money)as AvgPerUser,
sum(b.money) / nullif(count(a.id), 0) as AvgActUser,
count(b.id) / nullif(count(s.id), 0) as CovRate,
count(b.id) / nullif(count(a.id),0) as ConActRate,
count(b.id) filter (where s.subject = 'Math') * 1.0 / count(*) filter (where s.subject = 'Math') as ConRateMath
from Students s left join
(select b.id, sum(money) as money
from bills b
group by b.id
) b
on s.id = b.id left join
(select distinct a.id from active a
) a
on s.id = a.id
group by s.group;
Note: I don't think you want s.id in the GROUP BY. That really would not be aggregating anything.

Ignore duplicate data id in SQL Query?

How do I ignore duplicate data ids from query SQL results:
In this case I tried to combine several tables. Like this scheme that I made:
Transactions
----------------------------------------------------------------------------------------
id
user_id
type
amount
invoice_transaction (Relation to invoice)
created_at
updated_at
Users
----------------------------------------------------------------------------------------
id
name
email
phone
birth
address
picture
created_at
updated_at
Vouchers
----------------------------------------------------------------------------------------
id
code
amount
type
created_at
updated_at
Vouchers Transactions
----------------------------------------------------------------------------------------
id
user_id
voucher_id
created_at
updated_at
invoice
----------------------------------------------------------------------------------------
id
order_data
payment_id
last_total
status
created_at
updated_at
Payment
----------------------------------------------------------------------------------------
id
name
tax
created_at
updated_at
This is a query I made.
SELECT t.id, t.user_id, u1.name, u1.email, v.code, t.amount, t.type, t.created_at, t.invoice_transaction, i.status, p.name,
FROM transactions AS t
INNER JOIN users AS u1 on u1.id = t.user_id
LEFT JOIN vouchers_transaction AS vt on vt.user_id = u1.id
LEFT JOIN vouchers AS v on v.id = vt.voucher_id
LEFT JOIN invoice AS i on i.order_data = t.invoice_transaction
LEFT JOIN payment AS p on p.id = i.payment_id
WHERE t.type = 'buy'
ORDER BY id ASC
In this case I managed to get the data I wanted. But the results of the query contained duplicate transaction id data such as:
Result
---------------------------------------------------------------------------------------------------------------------------
id user_id name email code amount type invoice_transaction status payment_name
1 1 John Doe John#mail.com ycqs1 150 buy SCS11DAS success bank
1 1 John Doe John#mail.com ycqs1 150 buy SCS11DAS success bank
2 1 John Doe John#mail.com n1ksa 200 buy SCS12DAS success bank
Update
It seems like this happened because in the transaction voucher table there is no connection with the transaction table.
Example:
Voucher Transaction
---------------------------------------------------------------------------------------------------------------------------
id user_id voucher_id
1 1 1
2 1 2
3 2 3
Then each transaction will duplicate according to the number of vouchers used in the transaction vouchers, both transactions that use vouchers or not.
I know the best way is to change the database schema. But in this case can it still be done in this case or not?
Results
Result
---------------------------------------------------------------------------------------------------------------------------
id user_id name email code amount type invoice_transaction status payment_name
1 1 John Doe John#mail.com ycqs1 150 buy SCS11DAS success bank
1 1 John Doe John#mail.com sa31a 150 buy SCS11DAS success bank
2 1 John Doe John#mail.com n1ksa 200 buy SCS12DAS success bank
How do I ignore the duplicated transaction id?
Try using group by
SELECT t.id, t.user_id, u1.name, u1.email, v.code, t.amount, t.type, t.created_at, t.invoice_transaction, i.status, p.name,
FROM transactions AS t
INNER JOIN users AS u1 on u1.id = t.user_id
LEFT JOIN vouchers_transaction AS vt on vt.user_id = u1.id
LEFT JOIN vouchers AS v on v.id = vt.voucher_id
LEFT JOIN invoice AS i on i.order_data = t.invoice_transaction
LEFT JOIN payment AS p on p.id = i.payment_id
WHERE t.type = 'buy'
GROUP BY SELECT t.id, t.user_id, u1.name, u1.email, v.code, t.amount, t.type, t.created_at, t.invoice_transaction, i.status, p.name
ORDER BY id ASC
You will always get double ID's because the rows are different. The code and amount columns are all unique and you havent told SQL what to do with those columns. The group by Mahesh showed will work, if you change it to resolve the difference in the code and amount columns.
what amount do you want to see for ID 1? The lowest? highest? average? sum?.
either you have to remove those 2 columns from the query, or provide an aggregate function to resolve what to show
SELECT DISTINCT ON column1, column2, ...
FROM table_name;
The SELECT DISTINCT ON statement is used to return only distinct (different) values.

SQL: Select count of a record in right table with joins

I have 2 tables one for mobiles and other is for reviews. Reviews table store the reviews of a specific mobile against its mobile id.
Structure of mobiles table.
mobile_id | mobile_name
Structure of reviews table.
review_id | mobile_id | review_body
So far I have written this query.
SELECT c.*, p.review_body
FROM ((select mobile_id, mobile_name from mobiles
WHERE brand_id=1 limit 0,5) c)
left JOIN
(
SELECT mobile_id,
MAX(review_id) MaxDate
FROM reviews
GROUP BY mobile_id
) MaxDates ON c.mobile_id = MaxDates.mobile_id left JOIN
reviews p ON MaxDates.mobile_id = p.mobile_id
AND MaxDates.MaxDate = p.review_id
This query returns the first 5 mobiles from mobile table and their latest (one) review from review table. This is the result it returns.
mobile_id | mobile_name | review_body
Question: But i also want review_count with it. review_count should be equal to total number of reviews a mobile has in reviews table against its mobile_id.
So please tell me how it can be done with a single query that I already have. Any help would be appreciated as i am trying to do this since 24 hours.
I think this would work
SELECT c.*, p.review_body, MaxDates.review_count
FROM ((select mobile_id, mobile_name from mobiles
WHERE brand_id=1 limit 0,5) c)
left JOIN
(
SELECT mobile_id,count(review_id) review_count,
MAX(review_id) MaxDate
FROM reviews
GROUP BY mobile_id
) MaxDates ON c.mobile_id = MaxDates.mobile_id left JOIN
reviews p ON MaxDates.mobile_id = p.mobile_id
AND MaxDates.MaxDate = p.review_id

Group BY with multiple selects (Oracle)

Im having a problem using group by with multiple selects. I want to select the minimum bid offer price for each Auction. But I also have to get the name of the user who made that Bid. As you can see in the results, I get multiple results for each auction, and if I remove elements from the Groupby statement I get an error message. How can I groupy by ID_Auction and still show the name of the User? Thanks for the help
SELECT A.ID_AUCTION,MIN(B.PRICE) AS PRICE,U.NAME
FROM AUCTION A,BIDS B,USERS U,PRODUCT P
WHERE P.TYPE='CocaCola'
--Joins
and A.ID_AUCTION=B.ID_AUCTION
and BID.ID_USER=U.ID_USER
and A.ID_PRODUCT=P.ID_PRODUCT
GROUP BY A.ID_AUCTION,U.NAME;
ID_AUCTION PRICE NAME
---------- ---------- -------------- ------------------------------------------
27 25 Andrew
28 40 John
27 30 Michael
28 35 Peter
The Output I Desire :
ID_AUCTION PRICE NAME
---------- ---------- -------------- ------------------------------------------
27 25 Andrew
28 35 Peter
SELECT A.ID_AUCTION,MIN(B.PRICE) AS PRICE,U.NAME
FROM AUCTION A,BIDS B,USERS U,PRODUCT P
WHERE P.TYPE='CocaCola'
--Joins
and A.ID_AUCTION=B.ID_AUCTION
and BID.ID_USER=U.ID_USER
and A.ID_PRODUCT=P.ID_PRODUCT
GROUP BY A.ID_AUCTION,U.NAME;
Should probably be like:
SELECT A.ID_AUCTION, U.NAME, B.PRICE as PRICE
from AUCTION A
inner join (SELECT ID_AUCTION, NAME, MIN(Price) from Bids order by 1,2,3) B
ON a.ID_AUCTION = b.ID_AUCTION
inner join Users U
ON B.ID_USER = U.ID_USER
inner join Product P
ON A.ID_PRODUCT = P.ID_PRODUCT
WHERE P.TYPE = 'CocaCola'
GROUP BY A.ID_AUCTION, U.NAME
I've never seen joins work the way you did it, but that might be an Oracle thing...actually I think that's considered bad practice in most SQL arenas...
Give this a try, this will do the trick. It is ok with the coding style. Some old systems still work well with the ANSI-89 SQL style:
SELECT A.ID_AUCTION,
B.PRICE,
U.NAME
FROM AUCTION A,
BIDS B,
USERS U,
PRODUCT P
WHERE P.TYPE='CocaCola' --Joins
AND A.ID_AUCTION=B.ID_AUCTION
AND B.ID_USER=U.ID_USER
AND A.ID_PRODUCT=P.ID_PRODUCT
AND B.PRICE = (SELECT MIN(bids.PRICE) FROM BIDS --get only the bid with MIN price
WHERE bids.ID_AUCTION = A.ID_AUCTION);
select * from
(
SELECT A.ID_AUCTION,B.PRICE,U.NAME,
Dense_Rank() over (partition by ID_AUCTION order by Price Asc)AS Rank
FROM
AUCTION A
JOIN
BIDS B
ON A.ID_AUCTION=B.ID_AUCTION
JOIN
USERS U
ON BID.ID_USER=U.ID_USER
JOIN
PRODUCT P
ON A.ID_PRODUCT=P.ID_PRODUCT
WHERE P.TYPE='CocaCola')
where rank='1'
First should just group by A.ID_AUCTION and second on your select you could try a min(U.NAME)
SELECT A.ID_AUCTION,MIN(B.PRICE) AS PRICE,min(U.NAME)
FROM AUCTION A,BIDS B,USERS U,PRODUCT P
WHERE P.TYPE='CocaCola'
--Joins
and A.ID_AUCTION=B.ID_AUCTION
and BID.ID_USER=U.ID_USER
and A.ID_PRODUCT=P.ID_PRODUCT
GROUP BY A.ID_AUCTION;