TABLE : ITEMS
---------------------------------------
Item_ID Description
---------------------------------------
1 Vivel Satin Soap
2 Flake
3 Maggie
4 Mango Juice
---------------------------------------
TABLE : SALES
------------------------------------------------
Sale_ID Sale_Date Item_ID Quantity
------------------------------------------------
1 15-Feb-14 1 2
2 16-Feb-14 1 1
3 16-Feb-14 2 1
4 17-Feb-14 3 1
5 18-Feb-14 1 1
6 18-Feb-14 2 2
------------------------------------------------
I'm having trouble in constructing SQL query as the way i wanted.... Here, i have two
tables in the database as shown above. The "ITEMS" table is for Items' Description Look-up
and "SALES" table for Items' Sale Record Look-up. Now, my requirement is, i want to select a records
from both the tables to generate report (as shown in the following). Report should contain
Items Description and its corresponding Sum of Quantity.
REPORT
------------------------------------------------------
Item_ID Description Total_Quantity
------------------------------------------------------
1 Vivel Satin Soap 4
2 Flake 3
3 Maggie 1
4 Mango Juice (SHOULD BE NULL HERE)
------------------------------------------------------
I tried following SQL query and some more to generate the report but had a logical error....
so, help me to construct better!
1) SELECT I.Item_ID, I.Description, Sum(S.Quantity)
FROM ITEMS I
INNER JOIN SALES S ON I.Item_ID = S.Item_ID
ORDER BY I.Item_ID;
2) Select I.Item_ID, I.Description, Sum(S.Quantity)
From ITEMS I, SALES S
Where S.Item_ID IN (Select Item_ID from ITEMS)
Order by I.Item_ID;
3) etc..........
try this,
SELECT I.Description, Sum(S.Quantity)
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
GROUP BY I.Description
Instead of Inner just try with Left Join...
And you need to use Group by Clause
SELECT I.Item_ID, I.Description, Sum(S.Quantity) -- It will return Null for Mango Juice
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
Group By I.Item_ID, I.Description
ORDER BY I.Item_ID;
OR:
SELECT I.Item_ID, I.Description, CASE WHEN Sum(S.Quantity) IS NULL THEN 0 ELSE Sum(S.Quantity) END Quantity -- It will return 0 for Mango Juice
FROM ITEMS I
LEFT JOIN SALES S ON I.Item_ID = S.Item_ID
Group By I.Item_ID, I.Description
ORDER BY I.Item_ID;
Related
I have the following (simplified) tables
products - id name
order_products - quantity, product_id
I would like to order the rows from products table based on the sum of quantity column in order_products for every product
If order_products has these rows
quantity - product_id
2 - 555
2 - 555
6 - 666
3 - 777
I want the results to be ordered like that: 666, 555, 777
666 has 6 quantity, 555 has 4 and 777 has 3
I ended up using slightly modified version of the answer, as my requirement was to include products even if they don't have any relations in order_products table.
select p.*, coalesce(sum(op.quantity), 0) quantity_sold
from products p
left outer join order_products as op on op.product_id = p.id
group by p.id
order by quantity_sold desc
Just use ORDER BY and aggregate function
select p.product_id, p.name, sum(quantity) quantity_sold
from order_products op
join products p on op.product_id = p.product_id
group by p.product_id, p.name
order by sum(quantity) desc
I have two following tables:
products_table
id name
1 productA
2 productB
3 productC
inventory_table
id product_id amount
1 1 200
2 1 300
3 2 100
4 3 200
5 2 500
And the result I would like to get is
name total
productA 500
productB 600
productC 200
How could this be achieved using sql query?
Seems easy, first subSELECT query makes sums, parent one joins the names.
SELECT pt.name, n.total
FROM
(SELECT SUM(it.amount) as total, it.product_id
FROM inventory_table it
GROUP BY it.productID) n JOIN
products_table pt ON pt.id = n.product_id
I would try joining the two tables and use aggregation as
SELECT
p.name,
SUM(i.amount)
FROM product_table as p
LEFT JOIN inventory_table as i
ON p.id = i.product_id
GROUP by p.name
This is a simple inner join between the two tables, grouping by each Product and summing all its values.
select p.[name], Sum(i.amount) Amount
from product_table p join inventory_table i on i.product_id=p.id
group by p.[name]
I have the following relations:
A Product have multiple Images
A Product can have multiple Categories
A Category can have multiple Products
I want to get:
only the 'short_name' from the first category
only the first image url order_by another parameter
I have the following SQL, in PostgreSql:
SELECT DISTINCT ON(I.product_id) P.id, P.name, P.short_description,
CAT.short_name AS category, I.url
FROM products_product AS P
LEFT JOIN products_product_categories AS RPC ON P.id = RPC.product_id
LEFT JOIN categories_category AS CAT ON RPC.category_id = CAT.id
LEFT JOIN products_productimage AS I ON I.product_id = P.id
WHERE (P.is_active = TRUE)
My issue is that I don't know to limit left join and order by, I try to add LIMIT 1
LEFT JOIN categories_category AS CAT ON RPC.category_id = CAT.id LIMIT 1
but it is not working, I receive a code error 'syntax error at or near "LEFT"'
Category table
id | category_name | category_short_name
1 catA A
2 catB B
3 catC C
Product table
id | product_name | product_desc
1 P1 lorem1
2 P2 lorem2
3 P3 lorem3
ManytoMany: product_category
id product_id category_id
1 1 1
2 2 1
3 1 2
4 3 3
5 3 3
Image table
id url product_id order
1 lo1 1 4
2 lo2 1 0
3 lo3 1 1
4 lo4 2 0
For Product with id1 I expect to get:
name: P1, desc 'lorem1', category short_name : cat A, image url lo2
DISTINCT ON makes no sense without ORDER BY. As you want two different orders (on i.order for images and on cat.id for categories), you must do this in separate subqueries.
select p.id, p.name, p.short_description, c.short_name, i.url
from products_product p
left join
(
select distinct on (pcat.product_id) pcat.product_id, cat.short_name
from products_product_categories pcat
join categories_category cat on cat.id = pcat.category_id
order by pcat.product_id, cat.id
) c on c.product_id = p.id
left join
(
select distinct on (product_id) product_id, url
from products_productimage
order by product_id, order
) i on i.product_id = p.id
where p.is_active
order by p.id;
Two alternatives to write this query are:
subqueries with fetch first row only in the select clause
lateral left joins on subqueries with fetch first row only
Here I Have Two tables:
Orders
OrderId OrderName
1 Apple
2 Mango
Cust
Id Name OrderId Price
1 John 1 50
2 John 1 100
3 Mic 1 10
4 Mic 2 10
Sql Join Query:
SELECT Orders.CustName,Items.IteamName,Orders.Price
FROM Orders JOIN Items ON Items.Id = Orders.Id
Group By
SELECT Orders.CustName, SUM(Price) FROM Orders GROUP BY Orders.CustName
How can I Write Group by in Join?
You can do like this:
Select Orders.CustName, Items.IteamName, SUM(Orders.Price)
FROM
Orders JOIN Items ON Items.Id=Orders.Id
GROUP BY
Orders.CustName, Items.IteamName
The fields that you doesn't aggregate you put at the GROUP BYclause.
I am struggling to get my head around this sql.
I have a function that returns a list of items associated with a Bill of Materials BOM.
The result of the sql select
SELECT
BOM,
ITEMID,
QTY
FROM boms
WHERE
bom='A'
is
BOM | ITEMID | QTY
A | ITEMB | 1
A | ITEMC | 2
Now using that result set I am looking to query my salestable to find sales where ITEMB and ITEMC were sold in enough quantity.
The format of the salestable is as follows
SELECT
salesid,
itemid,
sum(qtyordered) 'ordered'
FROM salesline
WHERE
itemid='ITEMB'
or itemid='ITEMC'
GROUP BY salesid, itemid
This would give me something like
salesid | itemid | ordered
SO-10000 | ITEMB | 1
SO-10001 | ITEMB | 1
SO-10001 | ITEMC | 1
SO-10002 | ITEMB | 1
SO-10002 | ITEMC | 2
ideally I would like to return only SO-10002 as this is the only sale where all necessary units were sold.
Any suggestions would be appreciated. Ideally one query would be ideal but I am not sure if that is possible. Performance is not a must as this would be run once a week in the early hours of the morning.
EDIT
with the always excellent help, the code is now complete. I have wrapped it all up into a UDF which simply returns the sales for a specified BOM over a specified period of time.
Function is
CREATE FUNCTION [dbo].[BOMSALES] (#bom varchar(20),#startdate datetime, #enddate datetime)
RETURNS TABLE
AS
RETURN(
select count(q.SALESID) SOLD FROM (SELECT s.SALESID
FROM
(
SELECT s.SALESID, ITEMID, SUM(qtyordered) AS SOLD
FROM salesline s inner join SALESTABLE st on st.salesid=s.SALESID
where st.createddate>=#startdate and st.CREATEDDATE<=#enddate and st.salestype=3
GROUP BY s.SALESID, ITEMID
) AS s
JOIN dbo.BOM1 AS b ON b.ITEMID = s.ITEMID AND b.QTY <= s.SOLD
where b.BOM=#bom
GROUP BY s.SALESID
HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.BOM1 WHERE BOM = #bom)) q
)
This should return all sales with an exact match, i.e. same itemid and same quantity:
SELECT s.salesid
FROM
(
SELECT salesid, itemid, SUM(qtyordered) AS ordered
FROM salesline AS s
GROUP BY salesid, itemid
) AS s
JOIN
boms AS b
ON b.itemid = s.itemid
AND b.QTY = s.ordered
WHERE b.BOM='A'
GROUP BY s.salesid
HAVING COUNT(*) = (SELECT COUNT(*) FROM boms WHERE BOM='A');
If you want to return a sale where the quantity is greater than boms.qty youhave to change the join accordingly:
JOIN
boms AS b
ON b.itemid = s.itemid
AND b.QTY <= s.ordered
Untested...
You can do this aggregation and a having clause:
select salesid
from salesline sl
group by salesid
having sum(case when itemid = 'ITEMB' then 1 else 0 end) > 0 and
sum(case when itemid = 'ITEMA' then 1 else 0 end) > 0;
Each condition in the having clause is counting the number of rows with each item.
I think this may get you the results you need. You'll have to replace #BOM with your bom:
SELECT
DISTINCT salesid
FROM
salesline sl
INNER JOIN boms b ON
b.bom = #BOM
AND b.itemid = sl.itemid
GROUP BY salesid, itemid
HAVING SUM(qtyordered) >= b.qty
From what I gather, the first query is used to get the thresholds for returning qualifying sales? Based on your example data rows I assumed that there will only be one line per salesid + itemid (basically acting as a dual field primary key) in the salesline table? If that is true I don't think there is a need to do a SUM as you have in your second example query. Let me know if I'm mistaken in any of my assumptions and I'll adjust my answer.