SQL get first reord in each of a list of records - sql

HELP! Kind of new to SQL. I've been working with simple statements for a few years but I need a little advanced help. I know it can be done and will save me time.
Here is my example to try to find results:
select top 1 apples, color from fruits
where apples in ('gala', 'fuji', 'granny')
and (inStock is not null and inStock <> '')
In the above query I would get the first color in 'gala' apples and thats it. What I want is the first color in 'gala', the first in 'fuji', first in 'granny' and so on.
InStock isn't as important - it's just an additional filter in the search results.
What I want is a two column list. Left Column being apple types and right column being the first color result for each apple type.

You can use row_number() window ranking function to serialize apples wise colors in a specific order. Then choose first one from each group by selecting first rows.
with cte as
(
select apples, color ,row_number()over(partition by apples order by apples) rn from fruits
where apples in ('gala', 'fuji', 'granny')
and (inStock is not null and inStock <> '')
)
select apples, color from cte where rn=1

I think one issue you might have here is the concept of "first". A color is a categorical variable and tables don't typically attach meaning to a "first" or "last" value with a few exceptions. If you're dead set on returning the first row for each fruit, one easy way to get the result utilizes union all.
SELECT top 1 apples, color from fruits where apples = 'gala'
UNION ALL
SELECT top 1 apples, color from fruits where apples = 'fuji'
UNION ALL
SELECT top 1 apples, color from fruits where apples = 'granny'

Related

SQL Aggregation function to get concrete value

I need help with an aggregation functionality.
what I want to know is if it is possible to extract a concrete value from a grouped query on one of the columns I return, like this
STORE
fruit
color
stock
apple
red
30
apple
green
5
banana
yellow
40
berry
red
5
pear
green
5
SELECT SUM(stock), [?] FROM store GROUP BY fruit
[?] -> i need to take a concrete value, for example RED. but the SUM must have 35 in apples.
can this be done without a subquery?
Thanks
I expect this results
Column A
Column B
35
red
in this case the query does not make sense but for my personal case it does. I try to use STRING_AGG to take the data and make explode in my code, but its not the best way i think
I think you're looking for the GROUP BY clause. Try this:
SELECT SUM(stock), color
FROM store
GROUP BY color
This will return a list of all colors, and the sum of the stock for each color.
I'm not entirely clear what you mean by a "concrete value" (singlular) as there are potentially two or more values... and you did mention STRING_AGG(). Also, you omitted the "fruit" from the query, which made things a bit confusing. Nonetheless, this will get either one Color value or all color values using STRING_AGG() OR MAX() and without a sub-query:
-- the WITH is just a way to get your data into the query
;
WITH AdriansData AS
(SELECT * FROM (VALUES('apple', 'red', 30),
('apple', 'green', 5),
('banana', 'yellow', 40),
('berry', 'red', 5),
('pear', 'green', 5)
) AS X (fruit, color, stock)
)
SELECT fruit,
SUM(stock),
STRING_AGG(color, ', ') AS Colors,
MAX(color) AS JustOneColor
FROM AdriansData
GROUP BY fruit

How to select group of distinct rows from the table

Let's assume, a table has the following rows
ID Name Value
1 Apple Red
1 Taste Sour
2 Apple Yellow
2 Taste Sweet
3 Apple Red
3 Taste Sour
4 Apple Green
4 Taste Tart
5 Apple Yellow
5 Taste Sweet
I wonder, how can I select ID's corresponding to distinct combination of Apple and Taste? For example, ID=1 corresponds to red sour apple and ID=3 can be omitted in the query result. Similarly, ID=2 is for yellow sweet apple and ID=5 can be excluded from the query result, etc. A valid query result can be any of the following ID sets: (1,2,4), (1,4,5), (2,3,4) etc.
The query or the model could be improved with more understanding of the problem.
But assuming the model is correct and the problem is presented as this, this would be my quick approach.
SELECT MIN(a.ID) as ID
FROM Table a
INNER JOIN Table b ON a.ID = b.ID AND a.Name > b.Name
GROUP BY a.Value, b.Value
This query is joining the table with itself using the ID. But because you would have four lines for each possible combination (Ex.: Apple-Apple, Taste-Taste, Apple-Taste and Taste-Apple), you need to state not only that they are different (Because you would still have Apple-Taste and Taste-Apple) but that one of them is bigger than the other (That way you choose to have Apples on one side of the join and Tastes in the other). That's why there is the a.Name > b.Name.
You then group by both the values, stating that you don't want to have more than one combination of Apple values and Taste values. Resulting in only three lines.
The Select I think it depends of the RDBMS (I used SQL Server syntax), and it's selecting the lowest ID. You don't care, so you could choose Min or Max. Min results in lines with 1,2,4. Max would result in 3,4,5.

SELECT some column and count the rows in the same query

I want to select some rows and want to return those rows plus an additional column that display the count of selected rows. I am using a derived version of sql that doesnot allow me use OVER() AS function as discussed here . I want something like for each element in selected column ,I want a count of it in entire table Like
For Initial column like this :
Fruits
Apple
Mango
Fruits
Banan
Final returned values :
Fruits NewColumnwithCount
Apple 2
Mango 1
Apple 2
Banana 1
Like in selected colum called Fruits, Apple appear 2 times, banana 1 times and Mango 1 time (in the entire selected column called fruits)
use a GROUP BY as:
SELECT COUNT(FruitID), FruitName FROM Fruits GROUP BY FruitName;
UDPATE
SELECT FruitName,
(select count(fs.id) FROM Fruits fs where fs.id = f.id GROUP BY fs.FruitName) as 'count'
FROM Fruits f;
The subquery will return how many times the selected fruit is present
You are looking for window functions:
select fruit, count(*) over (partition by fruit) as NewColumnwithCount
from t;

SQL - Select top item from a grouping of two columns

I have a list of numbers attached to two separate columns, and I want to just return the first "match" of the two columns to get that data. I got close with this answer, but it only works with one field. I need it to work with a combination of fields. About ten second before I was ready to post.
Here's an example table "Item":
Item Color Area
Boat Red 1
Boat Red 2
Boat Blue 4
Boat Blue 5
Car Red 3
Car Red 4
Car Blue 10
Car Blue 31
And the result set returned should be:
Item Color Area
Boat Red 1
Boat Blue 4
Car Red 3
Car Blue 10
A much simpler way to do this:
select Item,
Color,
min(Area) as Area
from Item
group by Item
Color
Just use the MIN function with a GROUP BY.
SELECT Item, Color, MIN(area) AS Area
FROM Item
GROUP BY Item, Color
Output:
Item Color Area
Boat Blue 4
Boat Red 1
Car Blue 10
Car Red 3
SQL Fiddle: http://sqlfiddle.com/#!9/46a154/1/0
SQL tables represent unordered sets. Hence, there is no "first" of anything without a column specifying the ordering.
For your example results, the simplest query is:
select item, color, min(area) as area
from item i
group by item, color;
About ten seconds before I was ready to post the question, I realized the answer:
WITH summary AS (
SELECT i.item + ':' + i.color,
a.area,
ROW_NUMBER() OVER(PARTITION BY i.item + ':' + i.color,
ORDER BY i.item + ':' + i.color DESC) AS rk
FROM Item i
group by (i.item + ':' + i.color, i.Area)
SELECT s.*
FROM summary s
WHERE s.rk = 1
It's as simple as combining the two composite key fields into one field and grouping based on that. This might be a bit hackish so if anyone wants to suggest a better option I'm all for it.

Select unique record based on column value priority

This is a continuation of my previous question here.
In the following example:
id PRODUCT ID COLOUR
1 1001 GREEN
2 1002 GREEN
3 1002 RED
4 1003 RED
Given a product ID, I want to retrieve only one record - that with GREEN colour, if one exists, or the RED one otherwise. It sounds like I need to employ DISTINCT somehow, but I don't know how to supply the priority rule.
Pretty basic I'm sure, but my SQL skills are more than rusty..
Edit: Thank you everybody. One more question please: how can this be made to work with multiple records, ie. if the WHERE clause returns more than just one record? The LIMIT 1 would limit across the entire set, while what I'd want would be to limit just within each product.
For example, if I had something like SELECT * FROM table WHERE productID LIKE "1%" ... how can I retrieve each unique product, but still respecting the colour priority (GREEN>RED)?
try this:
SELECT top 1 *
FROM <table>
WHERE ProductID = <id>
ORDER BY case when colour ='GREEN' then 1
when colour ='RED' then 2 end
If you want to order it based on another color, you can give it in the case statement
SELECT *
FROM yourtable
WHERE ProductID = (your id)
ORDER BY colour
LIMIT 1
(Green will come before Red, you see. The LIMIT clause returns only one record)
For your subsequent edit, you can do this
select yourtable.*
from
yourtable
inner join
(select productid, min(colour) mincolour
from yourtable
where productid like '10%'
group by productid) v
on yourtable.productid=v.productid
and yourtable.colour=v.mincolour