Essentially I need to group unique product data into a single row when:
The supplier sku matches
The price for the products match (or) 1 of the product lines is equal to '0.00'
Here is a sample dataset set along with a working query for what I'm trying to accomplish. I'm simply not entirely comfortable that this is the best way to perform this query.
DECLARE #Test TABLE
(
SupplierSKU VARCHAR(25),
Description VARCHAR(50),
Quantity VARCHAR(25),
Price VARCHAR(25)
)
INSERT INTO #Test
SELECT '123', 'APPLES', '15', '0.00'
INSERT INTO #Test
SELECT '124', 'ORANGES', '10', '15.34'
INSERT INTO #Test
SELECT '123', 'APPLES', '5', '27.40'
INSERT INTO #Test
SELECT '125', 'PLUMS', '67', '34.86'
INSERT INTO #Test
SELECT '124', 'ORANGES', '10', '15.78'
INSERT INTO #Test
SELECT '125', 'PLUMS', '3', '34.86'
SELECT SupplierSKU, Description, SUM(Quantity) AS [Quantity], MAX(Price) AS [Price]
FROM
(
SELECT SupplierSKU, Description, SUM(CAST(Quantity AS INT)) AS [Quantity], (SELECT MAX(CAST(Price AS MONEY)) AS [Price] FROM #Test ti WHERE ti.SupplierSKU = t.SupplierSKU AND ti.Price = t.price AND ti.Price <> '0.00') AS [Price]
FROM #Test t
GROUP BY SupplierSKU, Description, Price
) pdata
GROUP BY pdata.SupplierSKU, pdata.Description
The desired results:
SupplierSKU Description Quantity Price
123 APPLES 20 27.40
124 ORANGES 10 15.34
124 ORANGES 10 15.78
125 PLUMS 70 34.86
This should produce the "desired output" but the desired output is not consistent with the textual objective. Why are quantity and price varchar. This solution assumes you convert quantity to integer on the SQL table.
SELECT SupplierSKU, Description, SUM(Quantity), P AS [Price]
FROM #test
Where [Price] > 0
GROUP BY SupplierSKU, Description, Price
First I repaired your own solution
SELECT SupplierSKU, Description, SUM(Quantity) AS [Quantity], MAX(cast(Price as money)) AS [Price]
FROM
(
SELECT SupplierSKU, Description, SUM(CAST(Quantity AS INT)) AS [Quantity],
(SELECT MAX(cast(PRICE as money)) from #test
where t.SupplierSKU = SupplierSKU and Description = t.Description and (t.price = '0.00' or t.price = price)) price
FROM #Test t
GROUP BY SupplierSKU, Description , price
) pdata
GROUP BY pdata.SupplierSKU, pdata.Description , price
Then I rewrote your solution to something more readable
SELECT suppliersku, description, sum(cast(quantity as int)) quantity, max(cast(price as money)) price FROM (
SELECT suppliersku, description, quantity, price FROM #test
WHERE price <> '0.00'
UNION ALL
SELECT t1.suppliersku, t1.description, t1.quantity, max(t2.price)
FROM #test t1
join
#test t2 ON t1.SupplierSKU=t2.SupplierSKU and t1.Description = t2.Description
WHERE t1.price = '0.00'
GROUP BY t1.suppliersku, t1.description, t1.quantity
) a
GROUP BY suppliersku, description, price
You may notice i get the right quantity of apples (15+5 = 20)
SELECT SupplierSKU, Description, SUM(Quantity) AS Qte, SUM(Price) AS Total
FROM #test t
GROUP BY SupplierSKU, Description
ORDER BY SupplierSKU
Does that gets you what you want?
Related
I am attempting to query unique results but am having issues with Query 2 as it pulls the Top 1 result of any ItemNumber instead of my desired ItemNumber from my select statement. I want to display all unique results from Query 1 & I want to display only 1 unique result from Query 2 where NULL Locations are prioritized. (1 'Y' SpecialItem associated per ItemNumber. I have mocked up a small example of my issue to keep the question from being too complex.
Table being used:
CREATE TABLE QA_TESTING (
ItemNumber varchar(255),
ItemName varchar(255),
Location varchar(255)
)
Data being used:
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('333', 'Apple', 'USA')
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('501', 'Apple', NULL)
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('501', 'Apple', NULL)
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('501', 'Apple', 'USA')
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('501', 'Apple', NULL)
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('405', 'Apple', 'USA')
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('405', 'Orange', 'USA')
Insert into QA_Testing (ItemNumber, ItemName, Location) Values ('501', 'Apple', 'USA')
My View:
IF EXISTS (SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_NAME = N'QA_TESTING_VW')
DROP VIEW QA_TESTING_VW
GO
CREATE VIEW dbo.QA_TESTING_VW
AS
(
(
--Query 1
Select DISTINCT QAT.ItemNumber, QAT.ItemName, Null AS SpecialItem, QAT.Location
From QA_Testing QAT
Where ItemName = 'Apple'
)
UNION ALL
(
--I Want to prioritize to show NULL over a non-null location in second query. If there is a null, show the null, otherwise, show the populated location. Only 1 row should be returned.
--Query 2
Select DISTINCT TOP 1 QAT.ItemNumber, QAT.ItemName, 'Y' AS SpecialItem, QAT.Location
From QA_Testing QAT
Where ItemName = 'Apple'
--ORDER BY Location ASC --ORDER BY TAKES TOO LONG
)
)
GO
My Select Statement:
--This has to stay in a simple format like so, with no additional unions, joins, etc.
Select * from QA_TESTING_VW where ItemNumber in ('501','830')
Outcome:
Expected Outcome:
there is comment "ORDER BY TAKES TOO LONG"
that's why I'm not quite sure.
As fuel for thought:
Select distinct QAT.ItemNumber, QAT.ItemName, O.SpecialItem, QAT.[Location]
From
(
Select QAT.ItemNumber
,QAT.ItemName
,QAT.[Location]
,row_number() over(partition by QAT.ItemNumber, QAT.ItemName order by QAT.[Location]) as LocationPriority
From QA_Testing QAT
Where ItemName = 'Apple'
) QAT
left join
(
select 'Y' AS SpecialItem
union all
select null
) O
on QAT.LocationPriority = 1
I have a table like this:
PARTNUMBER | QUANTITY | DESCRIPTION
'foo' 2 'a'
'foo' 2 'a1'
'bar' 2 'b'
'bar' 2 'b'
'bar' 2 'b1'
'bizz' 2 'c'
I'm trying to group by PARTNUMBER, aggregate by QUANTITY, and aggregate DESCRIPTION by most-frequent appearance.
I tried using a sub-query to aggregate DESCRIPTION by its most frequent occurrence, but I'm having some trouble getting it right, especially with GROUP BY.
Here is what I have:
SELECT SUM(QUANTITY) AS QUANTITY, PARTNNUMBER,
(SELECT TOP(1) [DESCRIPTION]
FROM [PBJobDB].[dbo].[DEVICES]
/*WHERE DESCRIPTION = t1.PARTNO ?? */
GROUP BY [DESCRIPTION], PARTNNUMBER
ORDER BY COUNT([DESCRIPTION]) DESC) as [DESCRIPTION]
FROM `database.table`
GROUP BY PARTNUMBER, [DESCRIPTION]
The subquery is not getting the most frequent DESCRIPTION by PARTNUMBER, and instead gives the most frequent DESCRIPTION in the whole table.
I would like the output to look like this:
PARTNUMBER | QUANTITY | DESCRIPTION
'foo' 4 'a'
'bar' 6 'b'
'bizz' 2 'c'
I tried below one, please check whether its working for you,
SELECT PARTNUMBER,SUM(QUANTITY) AS QUANTITY,
(
SELECT TOP 1 DESCP FROM
(SELECT [DESCRIPTION]'DESCP',COUNT(*)'CNT'
FROM testtable
WHERE PARTNUMBER = t1.PARTNUMBER
GROUP BY [DESCRIPTION]) A
GROUP BY DESCP,CNT HAVING CNT=MAX(CNT)
)as [DESCRIPTION]
FROM testtable T1
GROUP BY PARTNUMBER
This is what ended up working for me...
select distinct t1.PARTNUMBER , sum(t1.QUANTITY) AS QUANTITY, (
select TOP(1) [DESCRIPTION]
from [PBJobDB].[dbo].[DEVICES] AS t2
where t2.PARTNUMBER = t1.PARTNUMBER
group by [DESCRIPTION]
order by count(*) desc ) as [DESCRIPTION]
from `database.table` AS t1
/* WHERE `column` IS NULL AND `other_column` = 'some_value' */
GROUP BY t1.PARTNUMBER
You are looking for the mode. I would use two levels of aggregation:
select partnumber, sum(quantity) as total_quantity,
max(case when seqnum = 1 then description end) as description
from (select partnumber, description, sum(quantity) as quantity,
row_number() over (partition by partnumber order by sum(quantity) desc, description) as seqnum
from t
group by partnumber, description
) pd
group by partnumber;
I would use Sum() over to get total quantity. Below is the example that worked for me.
SELECT PARTNUMBER, QUANTITY, DESCRIPTION
FROM (
SELECT PARTNUMBER,SUM(Quantity) OVER (PARTITION BY PARTNUMBER ORDER BY CAST(PARTNUMBER AS VARCHAR(30)) ) Quantity,DESCRIPTION,R
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY PARTNUMBER ORDER BY COUNT(DESCRIPTION) DESC) R,
SUM(Quantity) Quantity, --OVER (PARTITION BY PARTNUMBER ORDER BY CAST(PARTNUMBER AS VARCHAR(30)) ) Quantity,
PARTNUMBER,
DESCRIPTION
FROM #Temp
GROUP BY PARTNUMBER,DESCRIPTION
) AS S
) AS S
WHERE R = 1
I'm currently summing across five columns that are of money data type. The columns Amount2, Amount3, Amount4, Amount5 need to have displayed as Rows with their sum showing accordingly.
Currently the results look like this on execution of the query:
but I need the results to be displayed like in this format:
Does anyone know a way of doing this?
I did try this but not managing to get it to work:
SELECT name, amount1, column
FROM
(
select
Name,
sum(Amount1) as Amount1,
sum(Amount2) as Amount2,
sum(Amount3) as Amount3,
sum(Amount4) as Amount4,
Sum(Amount5) as Amount5
from
#temp
group by
Name
) d
UNPIVOT
(
value
for column in (Amount2,Amount3,Amount4,Amount5)
) unpiv;
I get the following error:
Msg 156, Level 15, State 1, Line 54
Incorrect syntax near the keyword 'FROM'.
Msg 102, Level 15, State 1, Line 67
Incorrect syntax near 'd'.
Sample Data
Create table #temp
(
Name varchar(10),
Amount1 money,
Amount2 money,
Amount3 money,
Amount4 money,
Amount5 money
)
insert into #temp
(
Name,
Amount1,
Amount2,
Amount3,
Amount4,
Amount5
)
SELECT
'Test',
1,
NULL,
NULL,
4,
NULL
UNION ALL
SELECT
'Test1',
1,
NULL,
NULL,
NULL,
5
UNION ALL
SELECT
'Test2',
1,
NULL,
3,
NULL,
NULL
UNION ALL
SELECT
'Test',
1,
2,
NULL,
NULL,
NULL
select
Name,
sum(Amount1) as Amount1,
sum(Amount2) as Amount2,
sum(Amount3) as Amount3,
sum(Amount4) as Amount4,
Sum(Amount5) as Amount5
from
#temp
group by
Name
drop table #temp
You can simply use UNION ALL for each type Amount
; with cte as
(
select *
from #temp
)
select
Name,
sum(Amount1) as Amount1
from
cte
group by
Name
union all
select 'Amount2', sum(Amount2) from cte
union all
select 'Amount3', sum(Amount3) from cte
union all
select 'Amount4', sum(Amount4) from cte
union all
select 'Amount5', sum(Amount5) from cte
In SQL Server, the simplest (and generally most efficient) method is apply:
select v.*
from (select Name,
sum(Amount1) as Amount1,
sum(Amount2) as Amount2,
sum(Amount3) as Amount3,
sum(Amount4) as Amount4,
sum(Amount5) as Amount5
from #temp t
group by Name
) n cross apply
(values (Name, Amount1),
('Amount2', Amount2),
('Amount3', Amount3),
('Amount4', Amount4),
('Amount5', Amount5)
) v(Name, Amount)
where v.Amount is not null;
I'm new to using views, and I'm not exactly sure if what I want to do is possible using a view.
The first table is my original data file that I have imported into SQL.
I created a view with only the fruit and amount_from_us columns, and I'm having trouble figuring out how to include the amount in there. Normally, I'd use a where clause, but I don't know how I can do that at the same time as selecting the other data.
Here is what I have so far:
CREATE VIEW fruit_summary AS
SELECT fruit
, SUM(amount) AS amount
FROM original_table
WHERE bought_from_us = 'yes'
GROUP BY fruit
This gets me the fruit column and the amount_from_us column. I am however lost on how to get the date and total amount in there. Is this even possible using views or should I just create a table and use joins?
Try:
SELECT fruit,
[date],
SUM(amount) AS amount,
SUM(case when bought_from_us = 'yes' then amount else 0 end)
AS amount_from_us
FROM original_table
GROUP BY fruit, [date]
create table #original_table
(
[date] datetime,
fruit varchar(50),
amount money,
bought_from_us char(3)
)
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/18/2012', 'Apple', 10, 0);
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/18/2012', 'Apple', 25, 'yes');
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/18/2012', 'Orange', 32, 0);
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/18/2012', 'Banana', 8, 0);
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/18/2012', 'Banana', 235, 'yes');
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/17/2012', 'Apple', 65, 0);
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/17/2012', 'Apple', 4, 'yes');
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/17/2012', 'Orange', 56, 0);
insert #original_table([date], fruit, amount, bought_from_us)
values ('01/17/2012', 'Orange', 95, 0);
What you've asked for in the result is quite complex. To get the last record, Jan-17 Banana 0 0, you need something like this:
with date_fruit_table as
(
select date_table.[date], fruit_table.fruit
from
(select distinct fruit from #original_table) as fruit_table,
(select distinct [date] from #original_table) as date_table
)
select date_fruit_table.[date], date_fruit_table.fruit,
SUM(isnull(#original_table.amount, 0)) as amount,
SUM(case #original_table.bought_from_us when 'yes' then #original_table.amount else 0 end) as amount_from_us
from date_fruit_table
left outer join #original_table on #original_table.fruit = date_fruit_table.fruit
and #original_table.[date] = date_fruit_table.[date]
group by date_fruit_table.[date], date_fruit_table.fruit
order by date_fruit_table.[date] desc
SELECT fruit
, SUM(amount) AS amount
, SUM(amount_from_us) AS amount_from_us
, [Date]
FROM original_table
WHERE bought_from_us = 'yes'
GROUP BY fruit, [Date]
sorry about my first answer, now I realize what you need:
with CTE_fruit as (
SELECT fruit, date, SUM(amount) AS amount, NULL AS amountUS
FROM original_table
GROUP BY fruit, date
union
SELECT fruit, date, NULL AS amount, SUM(amount) AS amountUS
FROM original_table
WHERE bought_from_us = 'yes'
GROUP BY fruit, date
)
select fruit, date, sum(amount), sum(amountUS) from CTE_fruit
GROUP BY fruit, date
I think this will work
I want to write an efficient query which returns a list of fruits by type, the lowest price for the type of fruit and the name of the fruit. Right now, I have a query which return me the fruit type and the lowest price for that type (see below). But I am unable to get the name of the cheapest fruit.
Any idea how I can achieve that? Thanks.
CREATE TABLE Fruits (
[type] nvarchar(250),
[variety] nvarchar(250),
[price] money
)
GO
INSERT INTO Fruits VALUES ('Apple', 'Gala', 2.79)
INSERT INTO Fruits VALUES ('Apple', 'Fuji', 0.24)
INSERT INTO Fruits VALUES ('Apple', 'Limbertwig', 2.87)
INSERT INTO Fruits VALUES ('Orange', 'Valencia', 3.59)
INSERT INTO Fruits VALUES ('Pear', 'Bradford', 6.05)
SELECT type, MIN(price)
FROM Fruits
GROUP BY [type]
Use:
SELECT f.*
FROM FRUITS f
JOIN (SELECT t.type,
MIN(t.price) AS min_price
FROM FRUITS t
GROUP BY t.type) x ON x.type = f.type
AND x.min_price = f.price
I gather you're using SQL Server - if v2005 or newer, you could also use analytic/rank/windowing functions instead:
SELECT f.type, f.variety, f.price
FROM (SELECT t.type, t.variety, t.price,
ROW_NUMBER() OVER (PARTITION BY t.type ORDER BY t.price) AS rank
FROM FRUITS t) f
WHERE f.rank = 1
There are a number of ways to do this, one solution is below.
SELECT F2.type, f2.variety, f2.price
FROM
(
SELECT type, min(price) as price
FROM Fruits
GROUP BY [type]
) as MinData
INNER JOIN Fruits F2
ON (MinData.type = Type = F2.Type
AND MinData.price = F2.Price)
Keep in mind that if you have multiple items in a category with the same price at the minimum you will get multiple results.
There's a simple trick you can use for this sort of query if your table has a surrogate primary key. (Actually, you can do it without one, but it's more convoluted.)
The setup:
if object_id('tempdb..#Fruits') is not null drop table #Fruits
create table #Fruits (
[id] int identity(1,1) not null,
[type] nvarchar(250),
[variety] nvarchar(250),
[price] money
)
insert into #Fruits ([type], [variety], [price])
select 'Apple', 'Gala', 2.79 union all
select 'Apple', 'Fuji', 0.24 union all
select 'Apple', 'Limbertwig', 2.87 union all
select 'Orange', 'Valencia', 3.59 union all
select 'Pear', 'Bradford', 6.05
And now the SQL:
select * -- no stars in PROD!
from #Fruits a
where
a.id in (
select top 1 x.id
from #Fruits x
where x.[type] = a.[type]
order by x.price
)