Create a List of Products which miss a specific Version - sql

I have to create a list of products from ProductTable. The field which I am filtering is the VersionID.
So I have a Table of ProductIDs and VersionIDs. The Problem is that for every Version there is an entry in the database e.g.
ProductID | VersionID
1 | x
1 | y
1 | z
2 | y
The Product which contains Version x should not show up on this list, so in this Case only Product 2 should be listed.
Thanks for your help in advance!

you could try using a subquery where you get all ProdcutID that you dont want
select ProdcutID from PRODUCTTABLE where VersionID = x
and filter your query with not in subquery like this
select *
from PRODUCTTABLE
where ProdcutID not in (select ProdcutID
from PRODUCTTABLE
where VersionID = x)

You can try the following query:
SELECT *
FROM ProductTable p
WHERE NOT EXISTS (SELECT * FROM ProductTable p2 WHERE p2.ProductId = p.ProductId AND Version = x)
In a nutshell we select all products where another query for the same product -- check out where we use p and p2 -- with a specific version x does not yield a result.

You can do it in a single pass (no sub-query, etc), by aggregating and checking the contents of the aggregate don't contain an 'x'
SELECT
ProductID
FROM
ProductTable
GROUP BY
ProductID
HAVING
MAX(CASE WHEN VersionID = 'x' THEN 1 ELSE 0 END) = 0

Related

SQL to Merge Multiple Child Records into a single row with new columns

I have a table called OrderDetail. I also have a child table called PriceCategories.
Each OrderDetail can have multiple PriceCategories (eg A = $1, B = 2$, C = 3$, etc...)
I want to somehow allow a single resulting record when I am doing a SQL Query on OrderDetail joined to PriceCategories, but returning each record in PriceCategories as columns in a single row.
For example using a normal Join I would end up with.
OrderID | PriceCat | Amount
1 A 1
1 B 2
1 C 3
What I want to end up with is something like;
OrderId | CatAAmount | CatBAmount | CatCAmount
1 1 2 3
Is there anyway within a SQL statement that can achieve this?
Use a case statement -
SELECT order_id,
CASE
WHEN pricecat = 'A' THEN
amount
END AS cataamount,
CASE
WHEN pricecat = 'B' THEN
amount
END AS catbamount,
CASE
WHEN pricecat = 'C' THEN
amount
END AS catcamount
FROM table
Using pivot.
SELECT OrderID, [A] CatAAmount,[B] CatBAmount, [C] CatCAmount
FROM
(SELECT OrderID, PriceCat, Amount
FROM test) p
PIVOT
(
max (Amount)
FOR PriceCat IN
( [A],[B],[C])
) AS pvt;
If you have more categories you can simply add them in the 'FOR' and 'SELECT' clause.
Please refer http://sqlfiddle.com/#!18/e19ac/13/0

Get result true if all the rows have met the condition in sql

Basically i'm looking for solution for the condition, where table has the following rows and i want to select only those where condition is met by all the rows.
ID category flag
1 A 1
2 A 1
3 A 0
4 B 1
5 C 0
Expected Result is B where flag is true for its category.
I hope that my answer would be helpful to your problem. In the subquery, a list of the categories is created by filtering the flags.
SELECT *
FROM tablename a
WHERE a.category NOT IN (
SELECT b.category
FROM tablename b
WHERE b.flag=0)
You want the categories for which the minimum flag is 1 (meaning there is no flag = 0):
select category
from tablename
group by category
having min(flag) = 1
See the demo.
Results:
| category |
| -------- |
| B |
Use correlated subquery with not exists
select * from tablename a
where not exists (select 1 from tablename b where a.category=b.cateogry and flag=0)
Try this
select distinct category,flag from test where category in
(select t.category from (select category,flag from test
group by category,flag)t group by t.category having count(*)=1)
and flag=1;
If you have a separate table of categories, then not exists is often the fastest method:
select c.*
from categories c
where not exists (select 1
from t
where t.category = c.category and
t.flag = 0
);
In particular, this can take advantage of an index on (category, flag). If you don't have such a table, then forpas's solution is quite effective.

Select if then case with first record

Can you do something like this in SQL Server?
I want to select from a table which has some records with the same product_id in one column and a Y or N in another (in stock), and take the first one which has a Y where the product_id is the same, while matching the product_id_set from another table.
... ,
SELECT
(SELECT TOP 1
(product_name),
CASE
WHEN in_stock = 'Y' THEN product_name
ELSE product_name
END
FROM
Products
WHERE
Products.product_set = Parent_Table.product_set) AS 'Product Name',
...
Sample data would be
product_set in_stock product_id product_name
---------------------------------------------------
1 N 12 Orange
1 Y 12 Pear
2 N 12 Apple
2 N 12 Lemon
Output from product_set = 1 would be 'Pear' for example.
So there's kind of two solutions depending on the answer to the following question. If there are no records for a product id with an in_stock value of 'Y', should anything return? Secondly, if there are multiple rows with in_stock 'Y', do you care which one it picks?
The first solution assumes you want the first row, whether or not there is ANY "Y" value.
select *
from (select RID = row_number() over (partition by product_set order by in_stock desc) -- i.e. sort Y before N
from Products) a
where a.RID = 1
The second will only return a value if there is at least one row with a 'Y' for in_stock. Note that the order by (select null) is essentially saying you don't care which one it picks if there are multiple in_stock items. If you DO care the order, replace it with the appropriate sort condition.
select *
from (select RID = row_number() over (partition by product_set order by (select null)) -- i.e. sort Y before N
from Products
where in_stock = 'Y') a
where a.RID = 1
I don't know what the structure of the "parent table" in your query is, so I've simplified it to assume you have what you need in Products alone.
SELECT ISNULL(
(
SELECT TOP 1 product_name
FROM Products
WHERE Products.product_set = Parent_Table.product_set
AND Products.in_stock = 'Y'
), 'Not in the stock') AS 'Product Name'

showing items when 'x' is present

Ok, so hoping I can get some help here after searching with no joy.
So I have a key 'orderno' and each 'orderno' has multiple items. Each item has a status. I want to pull a Q that shows only the orderno's that contain an item that has status of 'x'
So If there are 3 items and only 1 is showing status 'x' I want to see all three items not just the one.
Essentially removing any order/items that do not show the x value.
So table1
orderno / Itemno / Itemstatus
1 1 y
1 2 x
2 1 z
3 1 y
3 2 x
3 3 y
4 1 y
4 1 y
EDIT:
So basically the letters represent open, closed, or inprogress... I want to see only order that have and item closed as well as an item in progress so I can see why the order is only showing partially complete from there. Still probably not making sense here. Grrrr.
I need to return the ORDER# and all item#'s for any order that contains an item with status of 'x'.
SELECT * FROM Order_Table
WHERE orderno IN
(SELECT orderno FROM Order_Table WHERE Itemstatus = 'x')
The Inner query returns all the orders with the status 'x' and the outer one return all details of those orders.
I prefer EXISTS to the IN or JOIN versions. It general faster.
Added a sqlfiddle.
CREATE TABLE table1(orderno INT, Itemno INT, Itemstatus CHAR(1))
INSERT INTO table1 VALUES
(1,1,'y')
,(1,2,'x')
,(2,1,'z')
,(3,1,'y')
,(3,2,'x')
,(3,3,'y')
,(4,1,'y')
,(4,1,'y')
SELECT *
FROM table1 a
WHERE EXISTS(SELECT 1
FROM table1 b
WHERE b.OrderNo = a.OrderNo
AND b.Itemstatus='x')

To find if a item's price has changed

This is probably easy to do but I have a table which list items by price and has a version number for each item, so there is duplicate items with the same itemID and item name but the different versions might have different prices. I wanted a simple sql statement to check which items prices have changed
itemid | item | price |version | date
1 a 1.13 1 2011-12-01
2 b 5.13 1 2011-12-01
3 c 3.66 1 2011-12-01
4 a 1.03 2 2012-01-09
5 b 5.13 2 2012-01-09
6 c 3.33 2 2012-01-09
There will be numerous versions so guess I need to some kind of comparison function but not sure where to start in SQL.
So the above example I would only want to fetch back item a and c as there price has changed from the previous version.
Try:
SELECT item, COUNT(DISTINCT price) prices
FROM yourTable
/* WHERE clause would go here */
GROUP BY item
HAVING COUNT(DISTINCT price) > 1
Optionally include:
WHERE version in (1,2)
- if you only want to compare the specific versions 1 and 2.
This gives you a list of items where the prices has changed from the previous version:
WITH V AS (
SELECT MAX(version) CurrentFileVersion
FROM yourTable
), C AS (
SELECT item, price, version
FROM yourTable INNER JOIN V ON yourTable.version = V.CurrentFileVersion
), P AS (
SELECT item, price, version
FROM yourTable INNER JOIN V ON yourTable.version = (V.CurrentFileVersion - 1)
)
SELECT C.item
FROM C INNER JOIN
P ON C.item = P.item
WHERE C.price <> P.price;
This even shows all the intermediate steps. I honestly can't make it any more simple or explicit to follow than this.
Try this
SELECT * FROM Prices T
where exists (
SELECT 1 from Prices
where item = T.item and version = T.version - 1 and price != T.price
)
Ps. change "Prices" with your table name
I'm going to assume you want this information to update your table with data from this table.
I would pull the most current version of each record inot a temp table or CTE. THen I would run a MERGE statement to insert any new records or update any where the price is different from the existing price.