Select columns with multiple purcahses in a given date - sql

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

Related

How to get all rows from one table which have all relations?

I have 3 tables:
companies (id, name)
union_products (id, name)
products (id, company_id, union_product_id, price_per_one_product)
I need to get all companies which have products with union_product_id in (1,2) and total price of products (per company) is less than 100.
What I am trying to do now:
select * from "companies" where exists
(
select id from "products"
where "companies"."id" = "products"."company_id"
and "union_product_id" in (1, 2)
group by id
having COUNT(distinct union_product_id) = 2 AND SUM(price_per_one_product) < 100
)
The problem I stuck with is that I'm getting 0 rows from the query above, but it works if I'll change COUNT(distinct union_product_id) = 2 to 1.
DB fiddle: https://www.db-fiddle.com/f/iRjfzJe2MTmnwEcDXuJoxn/0
Try to join the three tables as the following:
SELECT C.id, C.name FROM
products P JOIN union_products U
ON P.union_product_id=U.id
JOIN companies C
ON P.company_id=C.id
WHERE P.union_product_id IN (1, 2)
GROUP BY C.id, C.name
HAVING COUNT(DISTINCT P.union_product_id) = 2 AND
SUM(P.price_for_one_product) < 100
ORDER BY C.id
See a demo.
SELECT c.name FROM "companies" c
JOIN "products" p ON c.id = p.company_id
WHERE union_product_id IN (1, 2) AND price_for_one_product < 100
GROUP BY c.name
HAVING COUNT(DISTINCT p.name) =2
This would provide you all the company(s) name(s) which has provides both union_product_id 1 and 2 and the price_for_one_product/ price_per_one_product is less than 100.
Note: You might need to change price_for_one_product with price_per_one_product, as in question you have used price_per_one_product but db-fiddle link table defination has used price_for_one_product.

Select all customers loyal to one company?

I've got tables:
TABLE | COLUMNS
----------+----------------------------------
CUSTOMER | C_ID, C_NAME, C_ADDRESS
SHOP | S_ID, S_NAME, S_ADDRESS, S_COMPANY
ORDER | S_ID, C_ID, O_DATE
I want to select id of all customers who made order only from shops of one company - 'Samsung' ('LG', 'HP', ... doesn't really matter, it's dynamic).
I've come only with one solution, but I consider it ugly:
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company = "Samsung" )
EXCEPT
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company != "Samsung" );
Same SQL queries, but reversed operator. Isn't there any aggregate method which solves such query better?
I mean, there could be millions of orders(I don't really have orders, I've got something that occurs more often).
Is it efficient to select thousands of orders and then compare them to hundreds of thousands orders which have different company? I know, that it compares sorted things, so it's O( m + n + sort(n) + sort(m) ). But that's still large for millions of records, or isn't?
And one more question. How could I select all customer values (name, address). How can I join them, can I do just
SELECT CUSTOMER.* FROM CUSTOMER JOIN ( (SELECT...) EXCEPT (SELECT...) ) USING (C_ID);
Disclaimer: This question ain't homework. It's preparation for the exam and desire to things more effective. My solution would be accepted at exam, but I like effective programming.
I like to approach this type of question using group by and a having clause. You can get the list of customers using:
select o.c_id
from orders o join
shops s
on o.s_id = o.s_id
group by c_id
having min(s.s_company) = max(s.s_company);
If you care about the particular company, then:
having min(s.s_company) = max(s.s_company) and
max(s.s_company) = 'Samsung'
If you want full customer information, you can join the customers table back in.
Whether this works better than the except version is something that would have to be tested on your system.
How about a query that uses no aggregate functions like Min and Max?
select C_ID, S_ID
from shop
group by C_ID, S_ID;
Now we have a distinct list of customers and all the companies they shopped at. The loyal customers will be the ones who only appear once in the list.
select C_ID
from Q1
group by C_ID
having count(*) = 1;
Join back to the first query to get the company id:
with
Q1 as(
select C_ID, S_ID
from shop
group by C_ID, S_ID
),
Q2 as(
select C_ID
from Q1
group by C_ID
having count(*) = 1
)
select Q1.C_ID, Q1.S_ID
from Q1
join Q2
on Q2.C_ID = Q1.C_ID;
Now you have a list of loyal customers and the one company each is loyal to.

calculating sum from another table using SQL

I have a table (District) have columns (Id - District name) . And another table (delivery) have columns (quantity - district Id). can i have a result like a table with every district name in a column and sum of quantity in other column using sql?
I understand that this question will be closed as this site is not about doing homework
select a.district_name, b.total
from District as a
inner join
(
select district_id, sum(quantity) as total
from delivery
group by district_id
) as b
on a.id = b.district_id
Try below code
SELECT dis.district_name,SUM(del.quantity) as quantity
FROM district as dis
INNER JOIN delivery as del
ON dis.id = del.district_id
GROUP BY del.district_id
you can use this code:
SELECT ID, Name, SUM(Quantity) AS SumOfQuantity
FROM
(
SELECT District.ID, District.Name, Delivery.Quantity
FROM District, Delivery
WHERE District.Id = Delivery.DistrictID
) AS T1
GROUP BY ID, Name

Cross Group By and Max Date Script

I'm writing a script to pull a Group By and a MAX(CreatedOnDate) from two different tables but only return where table1's MAX(CreatedOnDate) is greater than table2's MAX(CreatedOnDate).
For example;
select MasterId, max(createdon) --Master id + latest product generated date
from product
group by MasterId
select contactId, max(createdon) --Contact id + latest edit date for that contact
from contactEdit
group by contactId
from contactEdit ce
join contactmaster cm
on ce.contactId = cm.contactid
join product p
on p.MasterId = cm.MasterId
Between these two tables there is a contactMaster table, the join of which is above also. I want to find a list of all Contacts who have had Edits made since the last Product was created relating to that Contact.
Something like;
where max(ce.createdon) > max(p.createdon)
i am not quite sure what your tables look like and what exactly you are trying to achieve, so this is a bit of a guess.
what you want to do is group the tables in subselects and then compare the maxdates:
with ce as (
select MasterId, max(createdon) maxco --Master id + latest product generated date
from product
group by MasterId
)
, prod as (
select contactId, max(createdon) maxco --Contact id + latest edit date for that contact
from contactEdit
group by contactId
)
, cm as (
select contactId, masterId, max(createdon) maxco --Master id + latest product generated date
from contactmaster
group by contactId, masterId
)
select contactId
from ce
join cm
on ce.contactId = cm.contactid
join product p
on p.MasterId = cm.MasterId
where ce.maxco > prod.maxco

Inner join summing up all rows instead of 1

I have 2 tables, one which contains Revenue data and one which contains Account data - the account data contains multiple rows per account ... the Revenue value assigned against FactPlanNo 327865 is $65,000 which is what I want to show, however because there are 4 rows in the RefGPNRoleMapping table for this account, it is multiplying $65,000 by 4
How do I stop this from happening so it brings back the following result:
AccountNumber AccountName Rev
0123456 MyAccount 65000 (instead of 260,000)
I currently have this query:
select
b.AccountNumber,
b.AccountName,
sum(a.Revenue) as rev
from mdfl.FactPlanNo a
inner join xyz.RefGPNRoleMapping b on
a.FactPlanNo = b.FactPlanNo
where b.FactPlanNo = '327865'
group by b.AccountNumber, b.AccountName
/* Revenue per "FactPlanNo" */
SELECT FactPlanNo
, Sum(Revenue) As rev
FROM mdfl.FactPlanNo
GROUP
BY FactPlanNo
/* Make it a subquery and join to that! */
SELECT b.AccountNumber
, b.AccountName
, revenues.rev
FROM (
SELECT FactPlanNo
, Sum(Revenue) As rev
FROM mdfl.FactPlanNo
GROUP
BY FactPlanNo
) As revenues
LEFT
JOIN xyz.RefGPNRoleMapping As b
ON b.FactPlanNo = revenues.FactPlanNo
WHERE b.FactPlanNo = '327865'