Counting the amount of relations to one table to another - sql

Very hard to create a good title for this.
Given the table products
productID
---------
892
583
388
And the table purchases
customerID productID
---------- ---------
56 892
97 388
56 583
56 388
97 583
How would I go about getting a table of all the costumers that have bought all products?

You can use group by and having:
select customerId
from purchases
group by customerId
having count(distinct productID) = (select count(*) from products);

Use GROUP BY clause with HAVING :
SELECT pr.customerID
FROM products p INNER JOIN
purchases pr
on pr.productID = p.productID
GROUP BY pr.customerID
HAVING COUNT(DISTINCT pr.productID) = (SELECT COUNT(*) FROM products);

Related

Access Cross tab Query

I have two tables.
I need to subtract the the number of items ordered from the quantity currently
recorded.
I can get the count() of the sales of each individual item like so:
SELECT SALES.PRODUCT_ID AS ORDERED_ID
,COUNT(SALES.PRODUCT_ID) AS ORDERED
FROM SALES
GROUP BY SALES.PRODUCT_ID
Which gives me:
ORDERED_ID ORDERED
1201 2
1202 2
1204 2
1205 3
1206 1
1207 2
1208 1
1209 1
1210 3
Getting the quantity is just a matter of
SELECT PRODUCT.PRODUCT_ID AS INVEN_ID
,PRODUCT.QUANTITY AS INVEN
FROM PRODUCT
Which gives me:
INVEN_ID INVEN
1199 5
1200 2
1201 33
1202 44
1203 55
1204 66
1205 77
1206 88
1207 99
1208 110
1209 121
1210 132
I've spent hours on this problem and gave up at what I thought should be the solution:
SELECT SUB1.INVEN - SUB2.ORDERED
FROM
(SELECT PRODUCT.PRODUCT_ID AS INVEN_ID
,PRODUCT.QUANTITY AS INVEN
FROM PRODUCT
)AS SUB1
,(SELECT SALES.PRODUCT_ID AS ORDERED_ID
,COUNT(SALES.PRODUCT_ID) AS ORDERED
FROM SALES
GROUP BY SALES.PRODUCT_ID
)AS SUB2
INNER JOIN SUB1 ON SUB1.INVEN_ID = SUB2.ORDERED_ID
However, access does not recognize that last join as a valid join and without it I just get a Cartesian product. If I try to retrieve quantity without a sub query and just try to SELECT product.quantity - SUB2.ORDERED access demands that I put product.quantity - SUB2.ORDERED in an aggregate function. When I do what it says it then tells me that product.quantity - SUB2.ORDERED can't be in an aggregate function. I'm at a loss.
EDIT:
Final Solution:
SELECT SUB1.INVEN_ID AS PRODUCT_ID
,SUB1.PRODUCT_NAME AS PRODUCT_NAME
,SUB1.PRICE AS PRICE
,SUB1.INVEN - NZ(SUB2.ORDERED,0) AS AVAILABLE
FROM
(SELECT PRODUCT.PRODUCT_ID AS INVEN_ID
,PRODUCT.PRODUCT_NAME AS PRODUCT_NAME
,PRODUCT.PRICE AS PRICE
,PRODUCT.QUANTITY AS INVEN
FROM PRODUCT
)AS SUB1
LEFT JOIN
(SELECT SALES.PRODUCT_ID AS ORDERED_ID
,COUNT(SALES.PRODUCT_ID) AS ORDERED
FROM SALES
GROUP BY SALES.PRODUCT_ID
)AS SUB2 ON SUB1.INVEN_ID = SUB2.ORDERED_ID
Your INNER JOIN should put after first subquery.
I think you are looking for LEFT JOIN,because PRODUCT table should be the master table.
if you use LEFT JOIN SUB2.ORDERED column might be NULL so use NZ function
Or IIF(ISNULL(SUB2.ORDERED),0,SUB2.ORDERED) to check.
You can try this.
SELECT SUB1.INVEN - NZ(SUB2.ORDERED,0)
FROM
(SELECT PRODUCT.PRODUCT_ID AS INVEN_ID
,PRODUCT.QUANTITY AS INVEN
FROM PRODUCT
)AS SUB1
LEFT JOIN
(SELECT SALES.PRODUCT_ID AS ORDERED_ID
,COUNT(SALES.PRODUCT_ID) AS ORDERED
FROM SALES
GROUP BY SALES.PRODUCT_ID
)AS SUB2 ON SUB1.INVEN_ID = SUB2.ORDERED_ID

Subtract from purchase and sale s table for found balance

I have two tables: table one Purchase and another sales table, actually I need balance using subtract two table, subtract sales from table Purchase. My code is given below
create table purchase(
id number(10) primary key,
name varchar2(10),
p_qty number(10)
);
and insert data :
insert into purchase values(01,'productB',235);
insert into purchase values(04,'productC',394);
insert into purchase values(05,'productD',381);
insert into purchase values(08,'productE',357);
insert into purchase values(09,'productF',389);
insert into purchase values(10,'productQ',336);
another table: Sales
create table sales(
id number(10),
s_qty number(10),
constraint pid_pk foreign key (id)REFERENCES purchase(id)
);
insert data to salse table :
insert into sales values(01,34);
insert into sales values(04,54);
insert into sales values(05,44);
insert into sales values(09,50);
insert into sales values(01,3);
insert into sales values(04,4);
insert into sales values(05,5);
insert into sales values(09,53);
insert into sales values(01,2);
insert into sales values(04,2);
insert into sales values(05,2);
insert into sales values(09,2);
insert into sales values(01,4);
insert into sales values(04,9);
insert into sales values(05,11);
insert into sales values(09,7);
and I have using two query
Query 1:
select id,name,sum(p_qty) as p_total from purchase group by id,name;
ID NAME P_TOTAL
5 productD 381
10 productQ 336
4 productC 394
1 productB 235
8 productE 357
9 productF 389
QUERY2:
select id,sum(s_qty) as s_total from sales group by id;`
ID S_TOTAL
1 43
4 69
5 62
9 112
NOW I Want to below the table for balance each item
ID NAME P_TOTAL S_TOTAL BALANCE
5 productD 381 62 319
4 productC 394 69 325
1 productB 235 43 192
9 productF 389 112 277
Hope this helps.
SELECT p.id, p.name, p.p_total, s.s_total,
p.p_total - s.s_total AS balance
FROM (select id, name, sum(p_qty) as p_total FROM purchase
GROUP BY id, name) p
INNER JOIN (select id, sum(s_qty) as s_total FROM sales
GROUP BY id) s
ON s.ID = p.ID;
You're almost there. Take the two queries you already have and join them together:
SELECT p.ID,
p.NAME,
p.P_TOTAL,
s.S_TOTAL,
p.P_TOTAL - s.S_TOTAL AS BALANCE
FROM (select id, name, sum(p_qty) as p_total
from purchase
group by id, name) p
INNER JOIN (select id, sum(s_qty) as s_total
from sales
group by id) s
ON s.ID = p.ID
Best of luck.
I Want to below the table for balance each item
You way you want the balance for each item, but you only show the balance for the items with sales.
If you want each item that has been purchased, you can use left join with subqueries:
select p.id, p.name, p_total, coalesce(s_total, 0),
(p_total - coalesce(s_total, 0)) as balance
from (select id, name, sum(p_qty) as p_total
from purchase
group by id,name
) p left join
(select id, sum(s_qty) as s_total
from sales
group by id
) s
on p.id = s.id;
If you want each item that has sales, then just use inner join.

PostgreSQL - Group by filter out specific rows

I have 3 tables in a Postgres 9.5 DB like below,
threshold
id threshold_amount
----------------------
111 100
112 200
113 80
customers - each customer has a threshold_id of threshold table
id customer_name threshold_id
--------------------------------
313 abc 111
314 xyz 112
315 pqr 113
charges - per customer there is charges so this table has customer_id
id customer_id amount post_date
------------------------------------
211 313 50 4/1/2017
212 313 50 4/30/2017
213 313 50 5/15/2017
214 314 100 3/1/2017
215 314 50 3/21/2017
216 314 50 4/21/2017
217 314 100 5/1/2017
218 315 80 5/5/2017
I want to query it and return the specific post_date with sum( amount ) == threshold_amount by ascending order of charges.id column,
The resultset look like below,
customer_id post_date
-----------------------
313 4/30/2017
314 4/21/2017
315 5/5/2017
I've tried sum( amount ) with group by customer_id and call the one separate the stored procedure from select clause and pass the amount, post_date and threshold_amount then created one temp table and insert post_date into it if the above condition get match and then again access that temp table but it seems something not valid so I want to know if some other solution or Can I do it in query?
Thanks
Your question is asking about an exact match for the threshold. This is basically a cumulative sum:
select cct.*
from (select ch.customer_id, ch.amount,
sum(ch.amount) over (partition by ch.customer_id order by post_date) as running_amount,
t.threshold_amount
from charges ch join
customers c
on ch.customer_id = c.id join
threshholds t
on c.threshold_id = t.id
) cct
where running_amount = threshold_amount;
try this:
select
c.customer_id,
c.post_date
from charges c
join customers cu on cu.id = c.customer_id
join threshold t on t.id = cu.threshold_id
where (select sum(cc.amount) from charges cc where cc.id <= c.id
and cc.customer_id = c.customer_id) = t.threshold_amount

How to group my query by name? P_Name

select ID_Sale,SaleDate,Branch_Name,P_Name,P_UnitPrice,QuantitySold,
sum (QuantitySold*P_UnitPrice) over (order by ID_Sale asc) AS RunningTotal
from tblP_Sales
INNER JOIN tblProduct_With_Img
ON tblP_Sales.P_ID_Sales = tblProduct_With_Img.P_ID
INNER JOIN tblBranches
ON tblP_Sales.BranchID = tblBranches.BranchID
--this group is not working ? how to work this ?
group by P_Name
This is the result without the GROUP BY clause:
Sale_ID Sale_Date Branch Item Name Pric/unit qty RUNTotal
1056 2016-11-10 Ajman Afghani Pulaw With Meat 26 1 26
1057 2016-11-10 Ajman Sada Rice With Chicken Boti 24 2 74
1058 2016-11-11 Ajman Afghani Pulaw With Meat 26 1 100
I think you're looking to add "PARTITION BY "
select ID_Sale,SaleDate,Branch_Name,P_Name,P_UnitPrice,QuantitySold,
sum (QuantitySold*P_UnitPrice) over (PARTITION BY P_Name order by ID_Sale asc) AS RunningTotal
from tblP_Sales
INNER JOIN tblProduct_With_Img
ON tblP_Sales.P_ID_Sales = tblProduct_With_Img.P_ID
INNER JOIN tblBranches
ON tblP_Sales.BranchID = tblBranches.BranchID

SQL query: count for all the reviews that each customer has written

Lets say I have one table called "REVIEWS"
This table has Reviews that customers have written for various products.
I would like to be able to get a "count" for all the reviews that each customer has written,
so I write:
SELECT count(*) AS counter
FROM reviews
WHERE customers_id = 12345
Now, my problem is that I wish to have a count like above BUT only for customers who have written a SPECIFIC product review
For instance,
SELECT customers_review
FROM reviews
WHERE
products_id = '170'
In summary, I wish to be able to get the customers TOTAL COUNT for every review they have written, but ONLY for customers who have written a review for a specific product.
select customers_id, count(*)
from reviews
where customers_id in
(select customers_id from reviews where products_id = '170')
group by customers_id;
SELECT customers_id, COUNT(*) AS counter
FROM reviews
WHERE customers_id IN(
SELECT customers_id
FROM reviews
WHERE
products_id = '170'
)
GROUP BY customers_id
This will pull any customer who wrote about product X, and then count up total number of reviews they posted.
Select customer_ID, Count(*)
FROM reviews
WHERE customer_ID in ( Select Customer_ID from reviews where products_id = '170')
Group By customer_ID
This should give you a list of all CustomerID's along with the Count of all their reviews, but it will limit it only to the customers who have left a review for product 170.
Just add to the end of your first query
WHERE EXISTS (
SELECT 1 FROM reviews AS r
WHERE r.customers_id = reviews.customers_id
AND product_id = '170')
GROUP BY reviews.customers_id
Not disagreeing with the approaches in this thread. But I think windowing/analytic SQL offer another way of looking at this problem. You can get the counts:
Count of Reviews by Customer on this
detail row
Count of Reviews By
product on this detail row
Count of
Reviews by this customer on this
product on this detail row
Any
details (the text of the review, the
review ID etc...)
SQL Statement
SELECT
revid,
CUSTID,
PRODID,
COUNT (*) OVER (PARTITION BY custid) ByCust,
COUNT (*) OVER (PARTITION BY prodid) ByProd,
COUNT (*) OVER (PARTITION BY prodid, custid) ByCustProd
FROM customer_reviews
ORDER BY custid, prodid
--OUTPUT--
1520 106 1900 16 604 3
4650 106 1900 16 604 3
2730 106 1900 16 604 3
4640 106 3900 16 254 1
6287 110 1900 28 604 2
5849 110 1900 28 604 2
5965 110 3900 28 254 2
6117 110 3900 28 254 2