POSTGRESQL - Finding specific product when - sql

I've attempted to write a query but I've not managed to get it working correctly.
I'm attempting to retrieve where a specific product has been bought but where it also has been bought with other products. In the case below, I want to find where product A01 has been bought but also when it was bought with other products.
Data (extracted from tables for illustration):
Order | Product
123456 | A01
123457 | A01
123457 | B02
123458 | C03
123459 | A01
123459 | C03
Query which will return all orders with product A01 without showing other products:
SELECT
O.NUMBER
O.DATE
P.NUMBER
FROM
ORDERS O
JOIN PRODUCTS P on P.ID = O.ID
WHERE
P.NUMBER = 'A01'
I've tried to create a sub query which brings back just orders of product A01 but I don't know how to place it in the query for it to return all orders containing product A01 as well as any other product ordered with it.
Any help on this would be very grateful.
Thanks in advance.

You can use conditional SUM to detect if one ORDER group have one ore more 'A01'
CREATE TABLE orders
("Order" int, "Product" varchar(3))
;
INSERT INTO orders
("Order", "Product")
VALUES
(123456, 'A01'),
(123457, 'A01'),
(123457, 'B02'),
(123458, 'C03'),
(123459, 'A01'),
(123459, 'C03')
;
SELECT "Order"
FROM orders
GROUP BY "Order"
HAVING SUM(CASE WHEN "Product" = 'A01' THEN 1 ELSE 0 END) > 0

I appreciated Juan's including the DDL to create the database on my system. By the time I saw it, I'd already done all the same work, except that I got around the reserved word problem by naming that field Order1.
Sadly, I didn't consider that either of the offered queries worked on my system. I used MySQL.
The first one returned the A01 lines of the two orders on which other products were ordered too. I took Alex's purpose to include seeing all items of all orders that included A01. (Perhaps he wants to tell future customers what other products other customers have ordered with A01, and generate sales that way.)
The second one returned the three A01 lines.
Maybe Alex wants:
select *
from orders
where Order1 in (select Order1
from orders
where Product = 'A01')
It outputs all lines of all orders that include A01. The subquery makes a list of all orders with A01. The first query returns all lines of those orders.
In a big database, you might not want to run two queries, but this is the only way I see to get the result I understood Alex wanted. If that is what he wanted, he would have to run a second query once armed with output from the queries offered, so there's no real gain.
Good discussion. Thanks to all!

Use GROUP BY clause along with HAVING like
select "order", Product
from data
group by "order"
having count(distinct product) > 1;

Related

How can I select multiple records from more that two tables

I am a complete beginner in SQL and need some help to learn. I have this learning material I found online and trying to write queries per the instructions. I did the first but got stuck on the rest of the queries. Can anyone please help me write any one of the queries below?
[]
Please help me learn how to do the rest.
b) Get aids and names of agents who have placed individual orders of at least $500 for any customer living
in Kyoto.
c) What cities do those customers live in, who enjoy discount under 10% and have ordered at least 1000
combs so far (in all their orders put together)?
d) What product names have been ordered by at least one customer based in Dallas through any agent based
in Tokyo?
e) Get the name, city, and total dollar amount of all orders placed by each customer, arranged in descending
order of the amounts.
Here is how I managed to do the first one.
a) Get pairs of all customer cids and agent aids, who live in the same city.
SELECT customer.cid, agent.aid FROM customers, agent WHERE customer.city = agent.city
RESULT
cid
aid
c001
a05
c004
a05
c002
a06
c003
a06
Try this one for b
SELECT distinct Agents.City -- Distinct becuase you dont want more then one of the same city being returned
FROM Agents
JOIN Orders
ON orders.aid = agents.aid
WHERE orders.cid = 'c002' -- Checks the orders table for any cid equal to c002

SQL command to filter based on multiple tables and criteria

I am trying to learn sql, its driving me nuts. I cannot seem to grasp the proper syntax to achieve my desired output. I am watching videos on udemy and reading books on basic sql trying to teach myself, but it seems they all fall short in helping me bridge this gap I seem to not be able to over come.
I have a pretty good handle on the basics of the SELECT, FROM, WHEN commands. I seem to be gaining knowledge on using aggregate functions, but I am by no means an expert.
I have two tables, "Orders" and "OrderDet". "Orders" contains the CustomerName and the OrderNo, and OrderDet contains everything else, like PartNo, DateFinished, OrderNo, etc.
I have a situation where I can have multiple customers order the same part number. I want to show all the last orders all customers placed.
For example
SELECT Orders.CustDesc, OrderDet.OrderNo, OrderDet.PartNo, OrderDet.DateFinished
FROM Orders
JOIN OrderDet ON Orders.OrderNo = OrderDet.OrderNo
ORDER BY OrderDet.PartNo, OrderDet.DateFinished
This query returns:
Customer OrderNo PartNo Date Finished
--------------------------------------------------------
Cust 1 5032 12345678-1 NULL
Cust 2 10032 12345678-1 2019-06-05 14:54:25.853
Cust 2 1048 12345678-1 2019-07-08 00:00:00.000
Cust 1 5028 12345678-1 2019-09-30 11:45:45.960
Cust 1 5029 12345678-1 2019-09-30 12:49:35.713
Cust 1 5030 12345678-1 2019-09-30 13:04:57.333
Cust 1 5031 12345678-1 2019-10-10 13:58:22.653
I'm still learning when and how to use aggregate function but seem to not be able to fully grasp the concept. I tried to use a MAX on the Date column and GROUP BY the Customer and PartNo, but unless I remove the Order Number, the output never collapses down to what I want.
For example I used:
SELECT Orders.CustDesc, OrderDet.PartNo, MAX(OrderDet.DateFinished)
FROM Orders
JOIN OrderDet ON Orders.OrderNo = OrderDet.OrderNo
GROUP BY Orders.CustDesc, OrderDet.PartNo
ORDER BY OrderDet.PartNo
Removing OrderDet.OrderNo from SELECT, and OrderDet.DateFinished from the Order By.
This returns the row output I desire, but lacking all the columns I want.
Customer PartNo Date Finished
--------------------------------------------
Cust 2 12345678-1 2019-07-08 00:00:00.000
Cust 1 12345678-1 2019-10-10 13:58:22.653
As soon as I try and add the OrderNo back into the mix, I get the same output as the first. I think I understand why this is happening because all the OrderNo's are unique and cannot get grouped, but I cant grasp how to over come this.
I understand this is a basic SQL command but I cannot seem to understand how to get the output I desire. In this example I wanted to only see the two rows of unique Customers based on the last date the PartNo was finished, but have the entire rows contents shown. Not just three columns.
Again, I am trying to learn this stuff and I can only read and re-read the same basic content to learn how to do this for so long. Everything I read seems to lack the info my brain seems to require for that "AH HA" moment.
Perhaps someone could help bridge this gap?
I am interpreting your question as wanting the most recent order for a given customer for each part that customer has ordered.
For this, I would recommend window functions:
select CustDesc, OrderNo, od.DateFinished
from (select o.custdesc, od.orderno, od.partno, od.datefinished,
row_number() over (partition by o.custdesc, od.partno order by od.datefinished desc) as seqnum
from Orders o join
orderdet od
on o.OrderNo = od.OrderNo
) od
where seqnum = 1;
order by od.PartNo, od.DateFinished

SQL-sum over dynamic period

I have 2 tables: Customers and Actions, where each customer has uniqe ID (which can be found in each table).
Part of the customers became club members at a specific date (change between the customers). I'm trying to summarize their purchases until that date, and to get those who purchase more than (for example) 200 until they become club members.
For example, I can have the following customer:
custID purchDate purchAmount
1 2015-05-12 100
1 2015-07-12 150
1 2015-12-29 320
Now, assume that custID=1 became a club member at 2015-12-25; in that case, I'd like to get SUM(purchAmount)=250 (pay attention that I'd like to get this customer because 250>200).
I tried the following:
SELECT cust.custID, SUM(purchAmount)totAmount
FROM customers cust
JOIN actions act
ON cust.custID=act.custID
WHERE act.clubMember=1
AND cust.purchDate<act.clubMemberDate
GROUP BY cust.custID
HAVING totAmount>200;
Is it the right way to "attack" this question, or should I use something like while loop over the clubMemberDate (which telling the truth-I don't know how to do)?
I'm working with Teradata.
Your help will be appreciated.

DB2 Select from two tables when one table requires sum

In a DB2 Database, I want to do the following simple mathematics using a SQL query:
AvailableStock = SupplyStock - DemandStock
SupplyStock is stored in 1 table in 1 row, let's call this table the Supply table.
So the Supply table has this data:
ProductID | SupplyStock
---------------------
109 10
244 7 edit: exclude this product from the search
DemandStock is stored in a separate table Demand, where demand is logged as each customer logs demand during a customer order journey. Example data from the Demand table:
ProductID | DemandStock
------------------------
109 1
244 4 edit: exclude this product
109 6
109 2
So in our heads, if I want to calculate the AvailableStock for product '109', Supply is 10, Demand for product 109 totals to 9, and so Available stock is 1.
How do I do this in one select query in DB2 SQL?
The knowledge I have so far of some of the imagined steps in PseudoCode:
I select SupplyStock where product ID = '109'
I select sum(DemandStock) where product ID = '109'
I subtract SupplyStock from DemandStock
I present this as a resulting AvailableStock
The results will look like this:
Product ID | AvailableStock
109 9
I'd love to get this selected in one SQL select query.
Edit: I've since received an answer (that was almost perfect) and realised the question missed out some information.
This information:
We need to exclude data from products we don't want to select data for, and we also need to specifically select product 109.
My apologies, this was omitted from the original question.
I've since added a 'where' to select the product and this works for me. But for future sake, perhaps the answer should include this information too.
You do this using a join to bring the tables together and group by to aggregate the results of the join:
select s.ProductId, s.SupplyStock, sum(d.DemandStock),
(s.SupplyStock - sum(d.DemandStock)) as Available
from Supply s left join
Demand d
on s.ProductId = d.ProductId
where s.ProductId = 109
group by s.ProductId, s.SupplyStock;

SQL - calculate consumption of materials based on recipe

I'm not sure how to ask my question, so I'll explain what I'm trying to do: I'm building an app in Delphi XE, which should calculate the consumption of raw materials, based on products recipes and orders.
I have 5 tables: Orders, OrdersContent, Products, Raw Materials and Recipes. Each order is composed of a few products, and each product has it's own recipe of raw materials.
I already summed up all products from all orders using sql in Query1.
This is the command for Query1:
select Products.Price,
OrdersContent.ID_Product, sum(OrdersContent.QNT) as QNT_Sum,
(Products.Price * sum(OrdersContent.QNT)) as Value
from Orders, OrdersContent, Products
where Orders.ID = OrdersContent.ID_Order
and Products.ID = OrdersContent.ID_Product
group by
OrdersContent.ID_Product, Products.Price
This returns:
|Price | ID_Product | QNT_Sum | Value |
----------------------------------------
| 2 | 122521 | 150 | 300 |
| 10 | 366547 | 10 | 100 |
| xxx | xxxxxx | xxx | xxxxx|
It's exactly what I want.
So now I'm wondering if there's a way to calculate the raw materials consumption also using sql, as the only other way I know how to do this is to iterate through the whole Query1 and calculate raw materials consumption for each record(product) individually, add it to a new table and then sum up the results, which is very time consuming.
I'm pretty sure there must be a more efficient way to do this, but have no clue as to how or where to search how to do it. I'm not asking for the code, but some pointers or links to tutorials or examples.
I hope I'm clear enough, if not please do ask for more info.
Add Raw Materials and Recipe to your FROM clause with the appropriate joins. Group by raw materials. Remove id_product and price from your group by statement. Change the aggregation in your select to sum(products.price*orderscontent.qnt).
I'm guessing at your column names in Recipes and Raw Materials but here's the general idea.
select Recipes.ID_RAW_MATERIALS,
sum(OrdersContent.QNT) as QNT_Sum,
sum(Products.Price * OrdersContent.QN)) as Value
from Orders, OrdersContent, Products, Recipes, RawMaterials
where Orders.ID = OrdersContent.ID_Order
and Products.ID = OrdersContent.ID_Product
and Recipes.ID_PRODUCT = Products.ID
AND Recipes.ID_RAW_MATERIAL = Rawmaterials.ID
group by Recipes.ID_RAW_MATERIALS