stackoverflowers.
I want to group a list by a field name and, as aggregate function, choose the most recent date. But I want to retain the value from a field price relative to the entry with that last date. Dates never repeat for the same name. Here is the example table...
id name date price
1 Orange 21/01 1,99
2 Orange 22/01 1,99
3 Orange 23/01 2,99
4 Orange 25/01 1,99
5 Apple 20/01 2,49
6 Apple 22/01 3,49
7 Apple 23/01 2,99
8 Banana 20/01 3,99
9 Banana 21/01 3,99
10 Banana 22/01 4,99
11 Banana 23/01 3,99
12 Banana 24/01 3,99
... and the desired result:
id name MAX(date) last_price
4 Orange 25/01 1,99
7 Apple 23/01 2,99
12 Banana 24/01 3,99
Is that possible to accomplish this with SQL group by clause? Using a nested select is slowing things down, as I have a big, big table.
You can do something like this:
select *
from table t1
inner join (
select name, max(date) as maxdate
from table
group by name
) t2 on t1.name = t2.name and t1.date = t2.maxdate
Related
I have an order line table that looks like this:
ID
Order ID
Product Reference
Variant
1
1
Banana
Green
2
1
Banana
Yellow
3
2
Apple
Green
4
2
Banana
Brown
5
3
Apple
Red
6
3
Apple
Yellow
7
4
Apple
Yellow
8
4
Banana
Green
9
4
Banana
Yellow
10
4
Pear
Green
11
4
Pear
Green
12
4
Pear
Green
I want to know how often people place an order with a combination of different fruit products. I want to know the orderId for that situation and which productReference was combined in the orders.
I only care about the product, not the variant.
I would imagine the desired output looking like this - a simple table output that gives insight in what product combos are ordered:
Order ID
Product
2
Banana
2
Apple
4
Banana
4
Apple
4
Pear
I just need data output of the combination Banana+Apple and Banana+Apple+Pear happening so I can get more insight in the frequency of how often this happens. We expect most of our customers to only order Apple, Banana or Pear products, but that assumption needs to be verified.
Problem
I kind of get stuck after the first step.
select orderId, productReference, count(*) as amount
from OrderLines
group by orderId, productReference
This outputs:
Order ID
Product Reference
amount
1
Banana
2
2
Apple
1
2
Banana
1
3
Apple
2
4
Apple
1
4
Banana
2
4
Pear
3
I just don't know how to move on from this step to get the data I want.
You can use a window count() over()
select *
from
(
select orderId, productReference, count(*) as amount
, count(productReference) over(partition by orderId) np
from OrderLines
group by orderId, productReference
) t
where np > 1
You need only the rows where an Order_Id has different products; you can do this many ways.
One way is to aggregate and filter to only rows where the min product <> the max product, then use a correlation to find matching orders:
select distinct t.Order_ID, t.Product_Reference
from t
where exists (
select *
from t t2
where t2.Order_ID = t.Order_ID
group by order_id
having Min(Product_Reference) != Max(Product_Reference)
);
See this demo fiddle
You could use STRING_AGG:
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver16
Here's an example:
SELECT orderID, STRING_AGG(productReference, ' ') products
FROM
(
SELECT DISTINCT orderID, productReference
FROM orderLines
) order_products
GROUP BY orderID
For each order ID, this pulls out the distinct products, then the STRING_AGG combines them into one field.
Output
orderID
products
1
Banana
2
Apple Banana
3
Apple
4
Apple Banana Pear
SQL fiddle example: http://sqlfiddle.com/#!18/8a677/6
I am trying to have all components that are part of a product appear on the same row as each other
I have two tables
PRODUCT
ID PRODUCTNUMBER DESCRIPTION TYPE STATUS KIT
1 (PK) 121 1 Apples and 1 Oranges FRUIT PACK YES Y
2 122 2 Brocolli & 2 Carrots VEG PACK NO Y
3 123 3 Strawberries and 3 Blueberries and 1 Pear FRUIT PACK YES Y
4 124 2 Plums and 1 Pears FRUIT PACK YES Y
5 125 4 Grapes and 2 Cabbage COMBO PACK YES Y
6 126 Apple FRUIT YES N
7 127 Orange FRUIT YES N
8 128 Pear FRUIT YES N
9 129 Onion VEG NO N
10 130 Blueberry FRUIT YES N
11 131 Strawberry FRUIT YES N
12 132 Plum FRUIT YES N
PRODUCTCOMPONENT
PRODUCT QTY
5 55
6 45
7 21
8 12
9 0
10 20
11 25
12 50
My SQL query should return:
SKU Description COMPONENT1 QTY1 COMPONENT2 QTY2 COMPONENT3 QTY3
121 1 Apples and 1 Oranges Apple 55 Orange 45
123 3 Strawberries and 3 Blueberries and 1 Pear Strawberries 25 Blueberry 20 Pear 12
124 2 Plums and 1 Pears Plum 50 Pear 12
I tried:
SELECT
PRODUCT.CODE, PRODUCT.DESCRIPTION,
PRODUCTCOMPONENT.PRODUCT, PRODUCTCOMPONENT.QTY
FROM
PRODUCT
INNER JOIN
PRODUCTCOMPONENT ON PRODUCTCOMPONENT.PRODUCT = PRODUCT.ID
WHERE
PRODUCT.STATUS = YES
AND PRODUCT.KIT = Y;
Any help would be appreciated
Okay, this is from memory, but I've verified the syntax with SQL Fiddle.
You are right that you need to start with PRODUCT and PRODUCTCOMPONENT. And the code you posted will give you the data you want -- but it won't have the answers in columns, just in rows.
So what you have is what I call a "rotation problem". You want to "swing" the data over 90 degrees (so to speak), and have multiple columns where you had multiple rows.
There is no automatic, built-in way to do this. But there are indirect ways.
What you're going to have to do is left-outer-join PRODUCTCOMPONENT to PRODUCT once for every set of columns you want to display component information.
If you have 2 columns, you'd need to do it twice. Since your max is 5, you'll need to do it 5 times.
This is why I asked how many components you could have per item. If you had an indefinite number, you'd be out of luck, because there just isn't a simple way to
automatically extend columns out to the right for as many sets of rows you happen to have. You have to do a new left join clause for every additional possible component!
Here's an example of the 2-column case, which should show you how to do the 5-column case:
-- In order to join to just the records from Row 1, we need to number them!
-- We'll do that in a CTE (Common Table Expression).
;
WITH Components as (
-- I don't know all the columns in PRODUCTCOMPONENT, but you presumably have a
-- parent and child ID. Substitute the true names of the columns for the
-- column names I'm using
SELECT ParentId
, ChildId
, Product -- I am assuming this is the product name
, Qty
-- The following line will assign a line number to each component within
-- a product. If there's a particular order you want the columns to appear in,
-- change the "Order by" part of the ROW_NUMBER() OVER expression.
, RowNumber = ROW_NUMBER() OVER (Partition By ParentId Order By ChildId)
FROM ProductComponent
)
SELECT Product.PRODUCTNUMBER as Code
, Product.DESCRIPTION
, Component1.Product as Component1
, Component1.Qty as Qty1
, Component2.Product as Component2
, Component2.Qty as Qty2
FROM Product
-- Note that since some products will have more components than others,
-- you need to left-join to the Components CTE to make sure that rows are
-- still returned even when they only have nulls.
LEFT OUTER JOIN Components as Component1
ON Product.ID = Component1.ParentID
AND Component1.RowNumber = 1
-- The second clause of the JOIN means that you'll only get rows back
-- from the CTE if the RowNumber assigned in the CTE is (in this case) 2.
LEFT OUTER JOIN Components as Component2
ON Product.ID = Component2.ParentID
AND Component2.RowNumber = 2
WHERE Product.STATUS = 'YES'
AND Product.KIT = 'Y';
I'm trying to write a query in Access 2010 based on the following simple data set:
**Lot Fruit**
1 Mango
1 Mango
1 Apple
1 Orange
2 Apple
2 Apple
2 Apple
3 Apple
3 Mango
4 Mango
4 Mango
4 Mango
5 Apple
5 Apple
I only want to extract those Lot no. where fruit has only one type within each Lot.
For example, say I want to get data where Fruit = "Apple", then it should only pull data where Lot has only "Apple" no other fruit in the same Lot.
In our example if I want all lot which have only Apple, then query should bring the following result.
Lot Fruit
2 Apple
2 Apple
2 Apple
5 Apple
5 Apple
I have tried various SQL queries but with no luck, any help will be appreciated.
Try this:
SELECT Lot
FROM mytable
GROUP BY Lot
HAVING COUNT(CASE WHEN Fruit <> 'Apple' THEN 1 END) = 0
Alternatively try:
SELECT DISTINCT Lot
FROM mytable AS t1
WHERE Fruit = 'Apple' AND
NOT EXISTS (SELECT 1
FROM mytable AS t2
WHERE t1.Lot = t2.Lot AND t2.Fruit <> 'Apple')
It's also possible to use LEFT JOIN:
SELECT DISTINCT Lot
FROM mytable AS t1
LEFT JOIN mytable AS t2 ON t1.Lot = t2.Lot AND t2.Fruit <> 'Apple'
WHERE t1.Fruit = 'Apple' AND t2.Lot IS NULL
I apologize if this problem has been posted, but I don't really know how to describe it properly except to use an example.
To simplify my problem, I've created the following tables.
Essentially, I would like to link
FRUIT.COLOUR_ID to COLOURSHAPES.VALUE
FRUIT.SHAPE_ID to CLOURSHAPES.VALUE
However, what I want to display is COLOURSHAPES.VALUE as 2 separate columns.
In addition, I would like to have each fruit displayed as many times as their availabilities exist.
FRUITNAME COLOUR SHAPE AVAILABILITY
ORANGE ORANGE ROUND METRO
ORANGE ORANGE ROUND LOBLAWS
TABLE #1: FRUIT
FRUIT_ID FRUITNAME COLOUR_ID SHAPE_ID
1 ORANGE 10 20
2 BANANA 11 21
3 APPLE 12 20
4 PEAR 13 20
TABLE #2: COLOURSHAPES
VALUE DESCRIPTION
10 ORANGE
11 YELLOW
12 RED
13 BROWN
20 ROUND
21 LONG
TABLE #3: AVAILABILITY
FRUIT_ID STORE
1 METRO
1 LOBLAWS
2 FRESHCO
3 METRO
4 FRESHCO
You can join to Table2 twice, once to get colour and again to get shape.
select T3.FRUIT_ID, T1.FRUIT_NAME, T3.STORE, T2A.DESCRIPTION, T2B.DESCRIPTION
from TABLE3 T3
join TABLE1 T1
left join TABLE2 T2A on T1.COLOUR_ID=T2A.VALUE
left join TABLE2 T2B on T1.SHAPE_ID=T2B.VALUE
I am still new to SQL and was wondering what would be the best option to get distinct category names from two different columns from the same table.
Example:
Table Name: Fruits
ID CAT1 CAT2
1 APPLE PEACH
2 PEACH GRAPE
3 APPLE GRAPE
4 ORANGE APPLE
5 PEACH PEAR
Desired Output
Distinct CAT
APPLE
PEACH
GRAPE
ORANGE
PEAR
I know that I would want to do a join where I name each table a letter like fruits a and fruits b so I match it via the ID but I cannot figure how to display it in one column only the distinct CAT from both columns.
You could query the distinct values of both columns separately and UNION (e.g. MySQL documentation) the results:
(SELECT DISTINCT CAT1 FROM Fruits)
UNION
(SELECT DISTINCT CAT2 FROM Fruits)
If you would have played with it little you would have get this already.
Select distinct cat from ( (Select cat1 as cat from fruits) union all (Select cat2 as cat from fruits)) q