sql group by only one column - sql

I have read many answers, but don't find my answer. How can i group my table in sql by only one column "Code"? my table:
Name Code quantity storename
name1 12345 1 A1
name1 12345 3 A2
name2 9009 40 A1
name2 9009 5 A3
name3 4004 3 A1
I want to see
Name Code quantity storename
name1 12345 4 A1
name2 9009 45 A1
name3 4004 3 A1

try this (change the order if it is important):
SELECT NAME
, SUM(QUANTITY) AS QUANTITY
, code
, storename
FROM example
GROUP BY NAME
, code

What you are showing would be
Select Name,
Code,
Sum(Quantity) as Quantity
Min(Storename) as Storename
From MyTable
Group by Name, Code
What is your logic on storename? I assumed the lowest (first value)

try this query
select Name, Code, count(quantity) asquantity, storename from tablename
group by Code,Name,storename

This will produce the desired output for the shown input.
SELECT min(name) name,
code,
sum(quantity) quantity,
min(storename) storename
FROM elbat
GROUP BY code;
But it's another question if this is useful. Name probably is dependent of code? (Like code is the ID and name is the name of a product?) If it is, we won't have a problem there. But summing the quantity from all stores but only associating it with one store, is probably misleading. The store in the result doesn't necessarily have the quantity in the result in stock.

You need to decide how you want to rollup the non-grouped fields within the group and then place aggregations on them.
For example, you have two stores in your dataset that are tied to the same code. If you grouped by code then you would have to pick how the stores are presented when rolled up, generally a max or min would be used. However, you may need to include Store in your grouping as it seems like a pretty important entity. I'll show you two examples one with store in the grouping and one with it being aggregated.
With quantity rolled up at the Code level.
SELECT
Name,
Code,
CodeQuantity = SUM(Qauntity),
MaxStore = MAX(StoreName)
FROM
MyTable
GROUP BY
Name,
Code
With quantity rolled up at the store level.
SELECT
Name,
Code,
StoreName,
StoreQuantity = SUM(Qauntity)
FROM
MyTable
GROUP BY
Name,
Code,
StoreName

Related

SQL statement, check if other rows have the same value

I have a SQL statement that imports my product inventory from a Access.MDB file. The select statement is below. (well a portion of it)
SELECT
Brand, DESCRIPTION AS Model,
SECONDDESCRIPTION AS Description,
PRODUCT AS [Product Code], TYPE AS Batch, INACTIVE,
CORE AS [Core Range],
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
You may notice that the select statement will minus any items that are on a customer order from the SOH values. for clarity below is the line that does just that.
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
The problem i have is, that 1 product code, can have multiple batches, and if an item only has a qty of 1 in each batch, and then the customer order column also contains a 1, this results in 1 - 1 = 0.
However the customer orders column is really indicating that only 1 of the product codes in on a customer order, not that specific batch.
Is there a way to check if that product code has already been "Selected" and has a Customer Order Qty against it and if it does then ignore the customer order qty against this next batch in the table?
To help explain it a little here is a rough idea of the table that would be imported.
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
1
Apples
587554
1
1
Bananas
1548777
1
0
so in the table above with my existing select statement, my results would be
Apples 4 in batch 123456
Bananas 1 in batch 1548777
As the next two lines of apples would actually end up with a value of 0 in batches 234567 and 587554
my program is set to then only return to the user values of items they can sell with a SOH qty > 0
so i need the final datatable in my program to look like this:
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
0
Apples
587554
1
0
Bananas
1548777
1
0
In my table Batch Number is the unique identifier and does not occur twice in the table.
Im working in VB.NET so if it could not be done in the SQL select statement i could be open to the idea of adjusting the values in the dataset datatable, however that would probably be made harder by the fact that the SQL Select statement i'm using never actually imports the CUSTORD column of data into my datatable. As i was trying to handle the SOH values directly at the select statement level.
Hope i have not confused anyone, and explained it as simple as possible.
I have no idea what your initial code has to do with the question. But let me assume that you have a table in the format shown in the question and you want to set on_hand to 0 for all but the first row for each product. You can use:
select product, batch_number, custord,
iif( t.batch_number = (select top 1 t2.batch_number
from t as t2
where t2.product = t.product
order by t2.on_hand desc, t2.batch_number
),
t.on_hand, 0
) as adjusted_on_hand
from t
order by product, on_hand desc, batch_number

PostgreSql - How to create conditional column with the filter on another column?

I want to add 1 more columns where segment out whether the customer had sold at least one product or not.
Data example:
ProductID Customer Status
1 John Not sold
2 John Not Sold
3 John Sold
My expect result
ProductID Customer Status Sold_at_least_1
1 John Not sold Yes
2 John Not Sold Yes
3 John Sold Yes
4 Andrew Not Sold No
5 Andrew Not Sold No
6 Brandon Sold Yes
This is an example data. Sorry for any inconvenience as I unable to extract data out. Btw, appreciating for any helps.
You can do a window count of records of the same customer that have status = 'Sold' in a case expression:
select
t.*,
case when sum( (status = 'Sold')::int ) over(partition by customer) >= 1
then 'Yes'
else 'No'
end
from mytable
NB: note that this does not magically create new records (as shown in your sample data). This query gives you as many records in the resultset as there are in the table, with an additionnal column that indicates whether each cutsomer has at least one sold item in the table.
Here is a demo provided by VBokšić (thanks).
Another option is to use bool_or() as a window function. If you can live with a boolean column rather than a varchar with Yes/No, this makes the expression even simpler:
select productid, customer, status,
bool_or(status = 'Sold') over (partition by customer) as sold_at_least_one
from mytable;
Online example: https://rextester.com/NDN54253

SELECT if any row within ID contains specific value

I have a DB with IDs and their classification (and much more columns that are useless for now),
Due to differences in unused columns, one ID may have different classifications like:
ID Classification
1001 A
1001 A
1002 A
1002 A
1002 B
What I need is to group IDs and put classification by the rule "If any of the lines within this ID is 'B'-classified, then the group (single row with this ID) is 'B'-classified, else - 'A'-classified.
So that ID 1001 = A, but ID 1002 = B.
I am aware of WHERE tab.field = ANY() function, but I have reciprocal situation - left part of comparison should be ANY, while right part should be hardcoded. I kind of assume, that as comparison result is boolean, than place of left\right parts is irrelevant, but I cannot figure out query-subquery relations.
Please help
You can use the count window function to do this.
select distinct id
,case when count(case when classification='B' then 1 end) over(partition by id) >=1 then 'B' else 'A' end as classified
from t
For the special case where the classification of interest is also the letter with the last alphabetical position, you can simply do:
SELECT
ID,
MAX(Classification)
FROM tab
GROUP BY ID;
You can simply find max of classification for each id:
select id,
max(classification)
from your_table
group by id;

Removing duplicate rows by selecting only those with minimum length value

I have a table with two string columns: Name and Code. Code is unique, but Name is not. Sample data:
Name Code
-------- ----
Jacket 15
Jeans 003
Jeans 26
I want to select unique rows with the smallest Code value, but not in terms of numeric value; rather, the length of the string. Of course this does not work:
SELECT Name, Min(Code) as Code
FROM Clothes
GROUP BY Name, Code
The above code will return one row for Jeans like such:
Jeans | 003
That is correct, because as a number, 003 is less than 26. But not in my application, which cares about the length of the value, not the actual value. A value with a length of three characters is greater than a value with two characters. I actually need it to return this:
Jeans | 26
Because the length of 26 is shorter than the length of 003.
So how do I write SQL code that will select row that has the code with the minimum length, not the actual minimum value? I tried doing this:
SELECT Name, Min(Len(Code)) as Code
FROM Clothes
GROUP BY Name, Code
The above returns me only a single character so I end up with this:
Jeans | 2
;WITH cte AS
(
SELECT Name, Code, rn = ROW_NUMBER()
OVER (PARTITION BY Name ORDER BY LEN(Code))
FROM dbo.Clothes
)
SELECT Name, Code
FROM cte
WHERE rn = 1;
SQLfiddle demo
If you have multiple values of code that share the same length, the choice will be arbitrary, so you can break the tie by adding an additional order by clause, e.g.
OVER (PARTITION BY Name ORDER BY LEN(Code), CONVERT(INT, Code) DESC)
SQLfiddle demo
Try this
select clothes.name, MIN(code)
from clothes
inner join
(
SELECT
Name, Min(Len(Code)) as CodeLen
FROM
clothes
GROUP BY
Name
) results
on clothes.name = results.name
and LEN(clothes.code) = results.CodeLen
group by clothes.name
It sounds like you are trying to sort on the numeric value of the Code field. If so, the correct approach would be to cast it to INT first, and use that for sorting/min functions (in a subquery), then select the original code in your main query clause.

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