so I have the task of returning the a companies information if and only if ALL of their products have been discontinued.
I have a Suppliers and a Products table. The Suppliers table has a ProductID column and the Products table has a ProductID and a Discontinued column that stores a bit (1 being true or 0 being false).
If anyone has a solution to this, that would be a life saver.
EDIT: the query I'm working with would be something like this
select
s.CompanyName, p.ProductName, p.Discontinued
from
Suppliers s
join
Products p on s.SupplierID = p.SupplierID
and the output would be something like this
CompanyName ProductName Discontinued
-------------------------------------------------------------
Exotic Liquids Chai 0
Exotic Liquids Chang 0
Exotic Liquids Aniseed Syrup 0
New Orleans Cajun Delights Chef Anton's Cajun Seasoning 0
New Orleans Cajun Delights Chef Anton's Gumbo Mix 1
Grandma Kelly's Homestead Grandma's Boysenberry Spread 0
Grandma Kelly's Homestead Uncle Bob's Organic Dried Pears 0
Grandma Kelly's Homestead Northwoods Cranberry Sauce 0
Tokyo Traders Mishi Kobe Niku 1
Tokyo Traders Ikura 0
but I only want it to return the suppliers with all discontinued products
I'm going out on a limb here, but I think you're trying to JOIN two tables on the ProductID.
If that's the case, then you SQL query would look something like this:
SELECT a.ProductID, b.Discontinued FROM Suppliers a
LEFT JOIN Products b ON (a.productID = b.productID)
WHERE b.Discontinued = true
select Suppliers.SupplierID, CompanyName from Suppliers
inner join Products on
Products.SupplierID = Suppliers.SupplierID
where Discontinued = 1
and Products.SupplierID not in
(select SupplierID from Products where Discontinued = 0)
group by Suppliers.SupplierID, CompanyName
Become a better developer in every language you use. Stop trying to do everthing at once. Break the problem into digestible pieces. And learn how to post good questions. You have a query question - how do you expect others to understand your issue and supply useful suggestions without knowing your schema and understanding how you use it. Sure - it's fairly simple in this case but a script that generates your tables, populates them with sample data, and includes whatever you have tried encourages others to respond.
So the first step is to answer the question "which supplies provide only discontinued products". Apparently you have all the information you need in Product. Something like:
select P.SupplierID from dbo.Products as P
group by P.SupplierID
having min(cast(P.Discontinued as tinyint)) = 1
order by P.SupplierID;
I think that is correct but it is still a guess. Sometimes a bit column gets "used" in opposition to the name. What does that do? For each group generated by the group by clause (supplier ID), it will determine the min value of Discontinued (casting is necessary since you cannot use min/max with bit). For a supplier with all discontinued products, that column must be 1 for all associated rows. Since 1 > 0, that means that all products of a supplier are discontinued. Grouping also gives us a distinct set of rows.
Now that you know how to generate a distinct set of SupplierID values, you should be able to apply that to any other query to get information about those suppliers. You can join, use IN, use exists - try all three if you want to really make this a learning experience.
I've got a query which gets the lists of customers who've made a purchase of the product for the current day
select Customer.customerName, sum(InvoiceDetail.itemPrice * InvoiceDetail.itemQuantity) as dailyPurchase from Invoice
inner join InvoiceDetail on Invoice.invoiceID = InvoiceDetail.invoiceID
inner join Customer on Invoice.customerID = Customer.customerID
inner join Item on InvoiceDetail.itemID = Item.itemID
inner join Branch on Branch.branchID = Invoice.branchID
inner join Region on Region.regionID = Branch.regionID
where
Invoice.inactive = 0 and InvoiceDetail.inactive = 0
and Item.itemTypeID = 3
and Region.regionCode = 'CR'
and cast(Invoice.invoiceDate as date) = convert(date, '01/08/2016', 103)
group by Customer.customerName
What I need is a table with a list of all the dates in the current month, listing ALL customers who have at least purchased the product ONCE. It should resemble something similar to this image here.
Any help on how to get started or a general idea of how to get the desired result, is much appreciated. Thanks!
Sample Data from Results:
customerName dailyPurchase
AGH COMMUNICATIONS 450.00
ARIEL AMARCORD SHOP 285.00
AKN COMMUNICATION 300.00
AWSDAC TELECOMMUNICATION 2850.00
BARLEY MOBILE & SERVICES 285.00
Table Structure - I'm sorry, I don't know an easier way to copy this.
First get the customers who have purchased the product atleast once this month alongwith date.
Then use pivot to get the result in the form that you want (as seen in image). Search stackoverflow for pivot in sql server, you will get good info.
Give some information about the table structure and sample data and I might be able to help you with the query to get the results.
Trying to return only the 1st supplier code and have all other fields unaffected.
`Select
Container.Part_Key,
Part.Part_No,
Part.Name,
Part.Revision,
Container.Quantity,
Container.Container_Status,
OP.Operation_No,
Opp.Operation_Code,
Part.Part_Status,
Supplier.Supplier_Code
From Part_v_Container as Container
Join Part_v_Part as Part
ON Part.Part_Key = Container.Part_Key
Join Part_v_Part_Operation as Op
On Op.Part_Operation_Key = Container.Part_Operation_Key
Join Part_v_Operation as OPP
On OPP.Operation_Key = OP.Operation_Key
Join part_v_approved_supplier as Approved
On Approved.part_key = container.part_key
Join common_v_Supplier as Supplier
On Supplier.supplier_no = Approved.Supplier_No
Where Container.Active = '1'
group by container.part_key`
There will be duplicate part numbers, revisions, etc. Not worried about that. I just want the part no to list only one approved supplier to the far right, even though for any given part, there are multiple approved suppliers listed in the database.
Furthermore, the order the database lists the approved suppliers does not matter.
Thanks!
Add a sub query in your select list
( select top 1 supplier.supplier_code
From supplier
Where Supplier.supplier_no = Approved.Supplier_No order by Supplier.supplier_no) as supplier code
This can be the last field in the select list
You could add An appropriate order by.
This would work in SQL Server
Good day all,
I am having difficulty understanding the mechanics of the GROUP BY AND HAVING clause and was hoping for some advice.
I am trying to query two tables - PRODUCTS and ORDER_ITEMS. The PRODUCT_ID column is used to link these two tables.
I wish to view products which have been ordered from a certain supplier (filtered using the SUPPLIER_ID column which is in ORDER_ITEMS); have been successfully ordered before (ORDER_STATUS 6 in ORDER_ITEMS);and which have not been deleted (RECORD_DELETED column in ORDER_ITEMS). I only use the PRODUCTS table to show the name of the product. Furthermore I only want distinct products returned, meaning I want to exclude any results which duplicate the PRODUCT_ID column
This is the query that I am using:
SELECT
PD.PRODUCT_ID,
PD.PRODUCT_NAME,
PD.BARCODE,
PD.SUPPLIER_BARCODE,
COUNT(PD.PRODUCT_ID) AS COUNTED,
ODI.ORDER_ITEM_ID
FROM PRODUCTS PD
INNER JOIN ORDER_ITEMS ODI
ON PD.PRODUCT_ID = ODI.PRODUCT_ID
WHERE ODI.SUPPLIER_ID = 34359738399
AND ORDER_STATUS = 6
AND ODI.RECORD_DELETED = 0
GROUP BY PD.PRODUCT_ID,PD.PRODUCT_NAME,PD.BARCODE,PD.SUPPLIER_BARCODE,ODI.ORDER_ITEM_ID
HAVING COUNT(ODI.PRODUCT_ID) = 1
ORDER BY PRODUCT_ID ASC
Unfortunately this is returning 502 records with many of them duplicating the PRODUCT_ID. If I remove the ORDER_ITEM_ID column from the query 175 records are returned. These 175 records are products that meet the criteria given above. The problem is that I also need to pull the ORDER_ITEM_ID from ORDER_ITEMS (along with some other columns).
I vaguely understand that when I include ORDER_ITEMS the query is going to group the data by the ORDER_ITEM column and so will count the PRODUCT_ID values based on each individual ORDER_ITEM_ID. This results in there always being a count of 1 for each product.
How does one get around this? Also, is there a more suitable way of carrying out this task which would allow me to include one ORDER_ITEM record for every duplicated product? Rather than omitting them altogether as I am doing above?
This is some of the data that is returned by the query above:
PRODUCT_ID,PRODUCT_NAME,BARCODE,SUPPLIER_BARCODE,COUNTED,ORDER_ITEM_ID
34359738628,ADCORTYL INTRA-ARTIC/DERMAL 10MG/ML 5ML,5099627022132,5012712000037,1,34359755708
34359739609,ARTELAC 3.2MG/ML EYE DROPS SOLN,5099627456722,5027519008933,1,34359741719
34359739626,ASACOLON 500MG SUPPOSITORIES,5099627516587,5015313012737,1,34359742783
34359739767,ATROVENT 250MCG/1ML UDV NEB SOLN,5099627639637,5012816012561,1,34359738421
34359739770,ATROVENT 500MCG/2ML UDV NEB SOLN,5099627460293,5012816012592,1,34359743524
34359739893,AZOPT 10MG/ML EYE DROPS SUSP,5099627831543,5015664002753,1,34359749091
34359739893,AZOPT 10MG/ML EYE DROPS SUSP,5099627831543,5015664002753,1,34359749687
34359739893,AZOPT 10MG/ML EYE DROPS SUSP,5099627831543,5015664002753,1,34359749715
34359739893,AZOPT 10MG/ML EYE DROPS SUSP,5099627831543,5015664002753,1,34359754053
34359740053,BACTIGRAS MED DRSS 10CMX10CM STERILE GMS,5099627672368,5000223421984,1,34359748101
34359740062,BACTROBAN 2% OINTMENT,5099627053914,5099211003165,1,34359755226
34359740558,BETNOVATE RD CREAM,5099627005692,5099211001642,1,34359752422
34359740558,BETNOVATE RD CREAM,5099627005692,5099211001642,1,34359738487
34359741045,BISODOL ANTACID TABS,5099627057707,5014398001438,1,34359750542
34359741995,BROLENE 0.1% EYE DROPS SOLN,5099627006323,50982790,1,34359746555
34359741995,BROLENE 0.1% EYE DROPS SOLN,5099627006323,50982790,1,34359751650
34359741995,BROLENE 0.1% EYE DROPS SOLN,5099627006323,50982790,1,34359751783
34359742132,BURINEX 1MG TABS,5099627551328,5702191004212,1,34359749705
34359742152,BUSCOPAN 20MG/ML SOLN FOR INJ,5099627006620,5012816018532,1,34359749083
In the example above, several records were returned with duplicate PRODUCT_ID values e.g ASACOLON 500MG SUPPOSITORIES
You need GROUP_CONCAT/LISTAGG equivalent in SQL Server. You can use XML, STUFF and correlated subquery as replacement.
If PRODUCT_ID is UNIQUE you can use:
WITH cte AS
(
SELECT
PD.PRODUCT_ID,
PD.PRODUCT_NAME,
PD.BARCODE,
PD.SUPPLIER_BARCODE,
ODI.ORDER_ITEM_ID
FROM PRODUCTS PD
JOIN ORDER_ITEMS ODI
ON PD.PRODUCT_ID = ODI.PRODUCT_ID
WHERE ODI.SUPPLIER_ID = 34359738399
AND ORDER_STATUS = 6
AND ODI.RECORD_DELETED = 0
)
SELECT PRODUCT_ID,
PRODUCT_NAME,
BARCODE,
SUPPLIER_BARCODE,
[COUNTED] = COUNT(PD.PRODUCT_ID),
[ORDER_ITEM_ID] = STUFF((SELECT CONCAT(',' , ORDER_ITEM_ID)
FROM cte c2
WHERE c2.PRODUCT_ID = c1.PRODUCT_ID
ORDER BY c2.ORDER_ITEM_ID
FOR XML PATH ('')), 1, 1, '')
FROM cte c1
GROUP BY PRODUCT_ID,PRODUCT_NAME,BARCODE,SUPPLIER_BARCODE
HAVING COUNT(PRODUCT_ID) = 1
ORDER BY PRODUCT_ID ASC;
LiveDemo_SimplifiedVersion
Otherwise correlate using multiple columns:
SELECT CONCAT(',' , ORDER_ITEM_ID)
FROM cte c2
WHERE c2.PRODUCT_ID = c1.PRODUCT_ID
AND c2.PRODUCT_NAME = c1.PRODUCT_NAME
AND ...
ORDER BY c2.ORDER_ITEM_ID
FOR XML PATH ('')), 1, 1, '')
I am working on an application to dispense liquids. here is the organization of the DB
CANISTER:
canister_id{PK}
ingredient_id{FK}
INGREDIENT:
ingredient_id{PK}
ingredient_name
DRINK:
drink_id{PK}
drink_name
INGREDIENTINSTANCE:
instance_id{PK}
drink_id{FK}
ingredient_id{FK}
amount
Each drink has multiple ingredients(held in the ingredientInstance table), but there are only 12 canisters. I am trying to write an SQL command that will gather all drinks that have ALL of their required ingredients currently in canisters.
So far, this is what I have.
SELECT DISTINCT Drink.drink_name
FROM Drink, ingredientInstance, Canister
WHERE (((ingredientInstance.drink_id)=[Drink].[drink_id])
AND ((ingredientInstance.ingredient_id)
IN (select ingredient_id FROM Canister)));
However, this is returning all drinks that have even a single ingredient available. What I am looking for is a way to ensure that for every associated ingredient in ingredientInstance, it is currently in a canister.
For example, let's say that drink1 requires ingredient1 and ingredient2. I want it to appear in the result if both of those ingredient IDs are present in the Canisters, but not if only one or zero ingredients are in the canister.
I'm sure it's something obvious, but I can't think of how to do this.
This is an example of a set-within-sets query. I advocate using aggregation with a having clause for this:
select drink.drinkname
from IngredientInstance ii join
Drink d
on ii.DrinkId = d.Drinkid left join
Canister c
on ii.IngredientId = c.INgredientId
group by drink.drinkname
having sum(iif(c.IngredientId is null, 1, 0)) = 0;
This is joining IngredientInstance and Drink just to get the drink name. It is then doing a left join to the Canister table. This keeps all the ingredients in the drinks along with matching ingredients (if any) in the canisters. If an ingredient is missing from Canister, then it has a NULL ingredientId.
The group by looks at the ingredients by drink. The final having clause counts the number of missing ingredients, and only returns drinks with no missing ingredients.
select d.* from drink d inner join
(select i.drink_id, sum(case when c.canister_id is null 1 else 0 end) as fullcanister
from ingredientinstance i left join canister c on c.ingredient_id=i.ingredient_id
group by i.drink_id) as id on id.drink_id=d.drink_id and id.fullcanister=0