How can I select only the max food_order_id? - sql

How can I select only the max food_order_id?
SELECT
o.food_order_id,
fo.user_id,
f.name,
f.price,
o.quantity,
o.subtotal
FROM food_order fo
INNER JOIN order_item o ON fo.food_order_id = o.food_order_id
INNER JOIN food_item f ON o.food_id = f.food_id
WHERE fo.user_id = 12;
if I want to update or delete the information selected from table with how will I do it?
tables:
CREATE TABLE food_item (
food_id SERIAL PRIMARY KEY,
name TEXT,
image TEXT,
description TEXT,
price INT
);
CREATE TABLE food_order (
food_order_id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(user_id)
);
CREATE TABLE order_item (
order_item_id SERIAL PRIMARY KEY,
food_id INT REFERENCES food_item(food_id),
food_order_id INT REFERENCES food_order(food_order_id),
quantity INT,
subtotal INT
);

In Postgres 13, you can use FETCH FIRST WITH TIES:
SELECT o.food_order_id, fo.user_id, f.name, f.price, o.quantity, o.subtotal
FROM food_order fo JOIN
order_item o
ON fo.food_order_id = o.food_order_id JOIN
food_item f
ON o.food_id = f.food_id
WHERE fo.user_id = 12
ORDER BY o.food_order_id DESC
FETCH FIRST 1 ROW WITH TIES;
In older versions, I would recommend:
SELECT *
FROM (SELECT o.food_order_id, fo.user_id, f.name, f.price, o.quantity, o.subtotal,
RANK() OVER (ORDER BY o.food_order_id DESC) as seqnum
FROM food_order fo JOIN
order_item o
ON fo.food_order_id = o.food_order_id JOIN
food_item f
ON o.food_id = f.food_id
WHERE fo.user_id = 12
) x
WHERE seqnum = 1;

Related

Oracle: MAX of SUM of Each Group

My scenario is to show the hotel room with the highest maintenance cost for each hotel branch by using subqueries. I have three separate tables: branch, room, and maintenance.
Table branch
id NUMBER(3) PRIMARY KEY
location VARCHAR2(20)
Table room
id NUMBER(3) PRIMARY KEY
room_number CHAR(4)
branch_id NUMBER(3)
Table maintenance
id NUMBER(3) PRIMARY KEY
room_id NUMBER(3)
cost NUMBER(4)
With my desired output being in the format
location | room_number | cost
-------------------------------
| |
| |
| |
I'm not sure how to select the max value per branch after adding the total costs of each room. Please advise.
You can use window functions:
select *
from (
select b.location, r.room_number, m.cost,
rank() over(partition by b.id order by m.cost desc) rn
from branch b
inner join room r on r.branch_id = b.id
inner join maintenance m on m.room_id = r.id
) t
where rn = 1
If a room might have several maintenances, then we need aggregation:
select *
from (
select b.location, r.room_number, sum(m.cost) as cost,
rank() over(partition by b.id order by sum(m.cost) desc) rn
from branch b
inner join room r on r.branch_id = b.id
inner join maintenance m on m.room_id = r.id
group by b.id, b.location, r.room_number
) t
where rn = 1
You can use ROW_NUMBER() analytic function along with joining those tables
SELECT location, room_number, cost
FROM (SELECT b.location,
r.room_number,
m.cost,
ROW_NUMBER() OVER(PARTITION BY r.branch_id ORDER BY m.cost DESC) AS rn
FROM branch b
JOIN room r
ON r.branch_id = b.id
JOIN maintenance m
ON m.room_id = r.id)
WHERE rn = 1
P.S. If ties(the equal values of costs) matter(should be included even if generation for extra rows of maximum cost values are not problem), then you can replace ROW_NUMBER() with DENSE_RANK()

Oracle query for customers who buy popular products

I have three tables: customer, order and line items. They are set up as follows:
CREATE TABLE cust_account(
cust_id DECIMAL(10) NOT NULL,
first VARCHAR(30),
last VARCHAR(30),
address VARCHAR(50),
PRIMARY KEY (cust_id));
CREATE TABLE orders(
order_num DECIMAL(10) NOT NULL,
cust_id DECIMAL(10) NOT NULL,
order_date DATE,
PRIMARY KEY (order_num));
CREATE TABLE line_it(
order_id DECIMAL(10) NOT NULL,
line_id DECIMAL(10) NOT NULL,
item_num DECIMAL(10) NOT NULL,
PRIMARY KEY (order_id, line_id),
FOREIGN KEY (item_id) REFERENCES products);
I need to write a query that selects customers, their names and addresses who have purchased items that have been bought by 3 or more people. I have the following query:
SELECT cust_account.cust_id, cust_account.first, cust_account.last, cust_account.address
FROM cust_account
INNER JOIN orders ON cust_account.cust_id = orders.cust_id
INNER JOIN line_it ON orders.order_id = line_it.order_id
GROUP BY cust_account.cust_id, cust_account.last
HAVING COUNT(line_it.item_num) = (
SELECT COUNT (DISTINCT order_num > 3)
FROM line_it
);
Do I even need to make it a subquery? I am a bit lost. Appreciate any help, thanks.
Start with "items bought by 3 or more people". You can get these by doing:
select li.item_id
from line_item li join
order_info oi
on li.order_id = oi.order_id
group by li.item_id
having count(distinct oi.customer_id) >= 3;
Now you want customers in this set. Hmmmm:
select distinct ca.*
from customer_account ca join
orderinfo oi
on ca.customer_id = oi.customer_id join
line_item li
on li.order_id = oi.order_id
where li.item_id in (select li.item_id
from line_item li join
order_info oi
on li.order_id = oi.order_id
group by li.item_id
having count(distinct oi.customer_id) >= 3
);
You can also express this with window functions:
select distinct ca.*
from (select ca.*, count(distinct customer_id) over (partition by li.item_id) as num_customers_on_item
from customer_account ca join
orderinfo oi
on ca.customer_id = oi.customer_id join
line_item li
on li.order_id = oi.order_id
) ca
where num_customers_on_item >= 3;
You can use the following query
SELECT distinct customer_account.* FROM line_item, order_info ,customer_account where item_id in (
--Selecting only item purchased 3 or more
SELECT item_id FROM line_item group by item_id having count(1) >=3
)
and line_item.order_id = order_info.order_id
and customer_account.customer_id = order_info.customer_id
;

SQL INNER JOIN entity

I want to execute this query :
-- The most expensive item sold ever
SELECT
c.itemID, c.itemName
FROM
item AS c
JOIN
(SELECT
b.itemID as 'itemid', MAX(b.item_initialPrice) AS 'MaxPrice'
FROM
buyeritem AS a
INNER JOIN
item AS b ON a.item_ID = b.itemID) AS d ON c.itemID = d.itemid
GROUP BY
c.itemID, c.itemName;
My item table looks like this:
create table item
(
itemID int IDENTITY(1000, 1) NOT NULL,
itemName varchar(15) NOT NULL,
Item_desc varchar(255),
Item_initialPrice MONEY,
ItemQty int,
ownerID int NOT NULL,
condition varchar(20) NOT NULL,
PRIMARY KEY (itemID),
FOREIGN KEY (ownerID) REFERENCES seller (sellerID)
);
The problem is that column item.itemID is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. I tried to add a group by clause at the end
group by c.itemID, c.itemName
but I still get the same error? I don't really know where the problem comes from.
I also have this query
-- The most active seller(the one who has offered the most number of items)
SELECT
a.ownerID, b.sellerName
FROM
item AS a
INNER JOIN
seller AS b ON a.ownerID = b.sellerID
GROUP BY
a.ownerID, b.sellerName
ORDER BY
COUNT(a.itemID) DESC;
I want to add itemQty along with the ownerID and sellerName from item table stated above, what would be the best way to achieve that?
Just write distinct instead of Group By as Group By will not work with out an aggregated function like sum,max etc. in select statement which is missing in your query.An example of this is second query which I have written
SELECT distinct c.itemID, c.itemName
FROM item AS c
JOIN (
SELECT b.itemID as itemid, MAX(b.item_initialPrice) AS MaxPrice FROM buyeritem AS a
INNER JOIN item AS b ON a.item_ID = b.itemID
GROUP BY b.itemID) as d
ON c.itemID = d.itemid ;
For second query
Select a.* from
(
SELECT a.ownerID, b.sellerName, count(distinct a.ITEM_ID) as item_qty
FROM item AS a
INNER JOIN seller AS b ON a.ownerID = b.sellerID
GROUP BY a.ownerID,b.sellerName
) a
order by item_qty DESC

Sql join solution is possible for below case?

Can we solve below case with joins, I have solved with window functions
Relation: In the tables below, each order in the Orders table, is associated with a given Customer through the cust_id foreign key column that references the ID column in the Customer table.
Question: Find the largest order amount for each salesperson and the associated order number, along with the customer to whom that order belongs and sales person name.
Create Table Salesperson
(
ID int,
name varchar(100),
age float,
salary money
);
Create Table Orders
(
Number int,
order_date datetime,
cust_id int,
salesperson_id int,
Amount money
);
Create Table Customer
(
ID int,
name varchar(100),
city varchar(100),
IndustryType varchar(100)
);
insert into Salesperson values
( 1,'Rohit',25,50000),
( 2,'Pramod',25,50000),
( 3,'Atul',25,50000);
insert into Orders values
( 1,getdate(),101,1,50000),
( 2,getdate(),101,1,500000),
( 3,getdate(),102,1,10000),
( 4,getdate(),101,2,5000),
( 5,getdate(),102,2,700000),
( 6,getdate(),102,2,10000);
insert into Customer values
( 101,'Altu','bhopal','IT'),
( 102,'bltu','bhopal','ITES'),
( 103,'cltu','bhopal','NW');
Solution on with window function:
with CTE_MaxAmount
as
(
select max(amount) over (partition by salesperson_id ) as amount,
dense_rank() over (partition by salesperson_id order by amount) as rowid,
cust_id,
salesperson_id,number
from Orders with(nolock)
)
select ct.amount,
ct.cust_id,
c.name as customername,
s.name as salesman,
ct.salesperson_id,
number as OrderNumbner
from Customer c
join CTE_MaxAmount ct
on (c.id = ct.cust_id)
join Salesperson s
on (s.id = ct.salesperson_id)
where rowid = 1;
I'm breaking with my personal policy not to answer homework questions because the question is an opportunity to show how easily English is translated into SQL. The question is phrased exactly as the query can be built up.
find the largest order amount for each salesperson
select max(Amount) as Amount, salesperson_id from Orders group by salesperson_id
and the associated order number
select o.Number, M.salesperson_id, M.Amount
from Orders as o join (
select max(Amount) as amount, salesperson_id
from Orders group by salesperson_id
) as M
on o.salesperson_id = M.salesperson_id
and o.Amount = M.Amount
along with the customer
select c.name, o.Number, M.salesperson_id, M.Amount
from Orders as o join (
select max(Amount) as amount, salesperson_id
from Orders group by salesperson_id
) as M
on o.salesperson_id = M.salesperson_id
and o.Amount = M.Amount
join Customer as c
on o.cust_id = c.ID
and sales person name
select s.name as 'salesperson',
c.name as 'customer',
o.Number, M.salesperson_id, M.Amount
from Orders as o join (
select max(Amount) as amount, salesperson_id
from Orders group by salesperson_id
) as M
on o.salesperson_id = M.salesperson_id
and o.Amount = M.Amount
join Customer as c
on o.cust_id = c.ID
join Salesperson as s
on o.salesperson_id = s.ID

How can this query be optimized?

I need to write this query in postgresql 9.3:
List the most popular movie in each country. The most popular movie/movies is the one that has got the highest average rating
across all the users of that country. In case of a tie, return all
movies order alphabetically. (2 columns)
Tables needed:
CREATE TABLE movie (
id integer,
name varchar(200),
year date
);
CREATE TABLE userProfile (
userid varchar(200),
gender char(1),
age integer,
country varchar(200),
registered date
);
CREATE TABLE ratings (
mid integer,
userid varchar(200),
rating integer
);
CREATE INDEX movie_id_idx ON movie (id);
CREATE INDEX userProfile_userid_idx ON userProfile (userid);
CREATE INDEX ratings_userid_idx ON ratings (userid);
CREATE INDEX ratings_mid_idx ON ratings (mid);
CREATE INDEX ratings_userid_mid_idx ON ratings (userid, mid);
Here is mine query:
CREATE TEMP TABLE tops AS SELECT country, name
FROM ratings AS r INNER JOIN userProfile AS u
ON r.userid=u.userid
INNER JOIN movie AS m ON m.id = r.mid LIMIT 0;
~10 min
CREATE TEMP TABLE avg_country AS
SELECT country, r.mid, AVG(rating) AS rate
FROM ratings AS r INNER JOIN userProfile AS u
ON r.userid=u.userid
GROUP BY country, r.mid;
~8 min
DO $$
DECLARE arrow record;
BEGIN
CREATE TABLE movie_names AS SELECT id, name FROM movie;
FOR arrow IN SELECT DISTINCT country FROM userProfile ORDER BY country
LOOP
CREATE TABLE movies AS SELECT mid FROM (SELECT MAX(rate) AS m_rate FROM avg_country
WHERE country=arrow.country) AS max_val CROSS JOIN LATERAL
(SELECT mid FROM avg_country
WHERE country=arrow.country AND rate=max_val.m_rate) AS a;
WITH names AS (DELETE FROM movie_names AS m
WHERE m.id IN (SELECT mid FROM movies) RETURNING name)
INSERT INTO tops
SELECT arrow.country, name FROM names ORDER BY name;
DROP TABLE movies;
END LOOP;
DROP TABLE movie_names;
END$$;
SELECT * FROM tops;
DROP TABLE tops, avg_country;
Thanks a lot in advance)
This is similar to kordirkos answer, but with one fewer subquery:
select country, movie_name, avg_rating
from (select u.country, m.name as movie_name, avg(r.rating) as avg_rating
rank() over (partition by u.country order by avg(r.rating) desc) as seqnum
from userProfile u join
ratings r
on u.userid = r.userid join
movie m
on r.mid = m.id
group by u.country, m.id -- `name` is not needed here because id is unique
) uc
where seqnum = 1;
Alternatively, if you want to get the list on one row per country:
select country, string_agg(movie_name, '; ') as most_popular_movies
from (select u.country, m.name as movie_name, avg(r.rating) as avg_rating
rank() over (partition by u.country order by avg(r.rating) desc) as seqnum
from userProfile u join
ratings r
on u.userid = r.userid join
movie m
on r.mid = m.id
group by u.country, m.id -- `name` is not needed here because id is unique
) uc
where seqnum = 1
group by country;
Use a plain, old-fashioned SQL - it is old but gold.
WITH q AS (
SELECT *,
dense_rank() over (partition by country order by avg_rating desc ) rank
FROM (
select u.country, m.name movie_name, avg( r.rating ) avg_rating
from userProfile u
join ratings r on u.userid = r.userid
join movie m on r.mid = m.id
group by u.country, m.name
) xx )
SELECT country, movie_name
FROM q WHERE rank <= 1