SQL not exist issue - sql

Having a bit of trouble dealing with not exist clause in a query.
I have three tables:
Meal
no_meal integer
type_meal varchar(255)
Consumed
no_meal integer
designation varchar(255)
quantity integer
Food
designation varchar(255)
quantity integer
type varchar(255)
Quantity in food is quantity stored and quantity in consumed is consumed quantity so, they will differ and thus natural inner join won't cut it.
Type of food can be 'drink' 'meat' 'fish' and so on.
Type of meal can be 'Breakfast' 'Lunch' 'Dinner'
I want a query that will tell me the drinks that have been consumed in all types of meals.
I've been toggling and testing code but can't get it right. At the moment I'm trying this:
SELECT Consumed.designation
FROM Consumed
WHERE NOT EXISTS
(SELECT type_meal
FROM Consumed, Food, Meal
WHERE Consumed.designation = Food.designation
AND Consumed.no_meal = Meal.no_meal
AND type = 'Drink'
ORDER BY Food.designation)
EXCEPT
(SELECT type_meal
FROM Meal);
How the hell do I get it right?
Thanks for input.
EDIT:
I'll add some data in order to make it clearer.
Food
Steak 100 Meat
Water 200 Drink
Coca cola 300 Drink
Meal
0001 Breakfast
0002 Lunch
0003 Dinner
Consumed
0001 Water 50
0002 Steak 20
0001 Coca cola 20
0003 Water 5
0002 Water 15
Now, I want to know which drink has been consumed in every meal, which will only give water.
Hope I cleared some minds about the problem

Twist your mind a little bit, and think with double negatives ....
I want [...] the drinks that have been consumed in all types of meals.
You want all drinks for which there are NO meal types for which that drink is NOT part of the meal type:
select distinct f.designation
from food f
where
type = 'Drink' and
not exists (
select *
from meal m1
where not exists (
select *
from meal m2
join consumed c on c.no_meal = m2.no_meal
where
m1.no_meal = m2.no_meal and
c.designation = f.designation
)
)
This is called relational division.

Now I understand what you want...
SELECT designation
FROM Food
WHERE designation IN (
SELECT designation
FROM Consumed
GROUP BY designation
HAVING Count(DISTINCT no_meal) = (
SELECT Count(*) FROM Meal
)
)
WHERE type = 'Drink'

I want a query that will tell me the drinks that have been consumed in all types of meals.
Your edit did clear things up. Note that following query will not work if the combination Designation, Typein Consumedis not unique but I'm guessing it will be.
SELECT
c.Designation
FROM
(SELECT
c.Designation
FROM
Consumed c
INNER JOIN
Meal m ON m.no_meal = c.no_meal
GROUP BY
c.Designation
HAVING
COUNT(*) = (SELECT COUNT(*) FROM Meal)) c
INNER JOIN
Food f ON f.Designation = c.Designation
WHERE
f.Type = 'Drink'

select *
from food f inner join
consumed c_1 on c_1.designation = f.designation
where type='Drink' and
not exists -- to filter out drinks that are not a part of all the meals
(select 1
from consumed c_2 inner join
meal m_1 on m_1.no_meal = c_2.no_meal
where c_1.no_meal = c2.no_meal and
c_1.designation = c2.designation and
not exists (select 1
from meal m_2
where m_1.no_meal = m_2.no_meal))

I want a query that will tell me the drinks that have been consumed in all types of meals.
Here is the model structure and insertions you suggested:
USE SqlTests
GO
CREATE TABLE Meal (
no_meal int
, type_meal nvarchar(255)
)
GO
insert into Meal (no_meal, type_meal)
values (1, N'Breakfast')
GO
insert into Meal (no_meal, type_meal)
values(2, N'Lunch')
GO
insert into Meal (no_meal, type_meal)
values(3, N'Dinner')
GO
CREATE TABLE Consumed (
no_meal int
, designation nvarchar(255)
, quantity int
)
GO
insert into Consumed (no_meal, designation, quantity)
values (1, N'Water', 50)
GO
insert into Consumed (no_meal, designation, quantity)
values (2, N'Steak', 20)
GO
insert into Consumed (no_meal, designation, quantity)
values (1, N'Coca cola', 20)
GO
insert into Consumed (no_meal, designation, quantity)
values(3, N'Water', 5)
GO
insert into Consumed (no_meal, designation, quantity)
values(2, N'Water', 15)
GO
CREATE TABLE Food (
designation nvarchar(255)
, quantity int
, [type] nvarchar(255)
)
GO
insert into Food (designation, quantity, [type])
values (N'Water', 200, N'Drink')
GO
insert into Food (designation, quantity, [type])
values (N'Steak', 100, N'Meat')
GO
insert into Food (designation, quantity, [type])
values (N'Coca cola', 200, N'Drink')
GO
Then, selecting with the proposed SELECT:
select c.designation
from Consumed c
inner join Meal m on m.no_meal = c.no_meal
inner join Food f on f.designation = c.designation and f.[type] LIKE N'Drink'
group by c.designation
having COUNT(c.designation) = (select COUNT(type_meal) from Meal)
Returns (at least on my database engine (SQL Server Express 2005)
Water
Is my information data correct?

Related

SQL Server Stored Procedure for Menu Performance Report

I have four tables in my SQL database i.e MenuItems, Categories, Invoices and InvoiceDetails. Now what I want is to show the menu performance report for a certain date i.e total Qty and total Amount for
each menu item for a specific date. It shows the desired result without the date in the where clause but excludes menu items with null values.
Here is my stored procedure:
CREATE PROCEDURE spGetMenuPerformanceByDay
#Date date,
#Terminal int
AS
BEGIN
SELECT
M.Name,
ISNULL(SUM(D.Amount), 0) AS Amount,
ISNULL(SUM(D.Qty), 0) AS Qty
FROM
MenuItems AS M
JOIN
Categories AS C ON C.Id = M.CategoryId
LEFT JOIN
InvoiceDetails AS D ON M.Id = D.ItemId
LEFT JOIN
Invoices I ON I.Id = d.InvoiceId
WHERE
#Terminal IN (I.TerminalId, C.TerminalId)
AND CONVERT(date, I.Time) = #Date
OR NULL IN (Amount, Qty)
GROUP BY
M.Name, M.Id, D.ItemId
ORDER BY
(Qty) DESC
END
The result this stored procedure returns on adding Date in where clause:
Item
Amount
Qty
KOFTA ANDA
1950
3
HOT N SOUR SOUP
550
1
CHICKEN CHOWMEIN
250
1
CHICKEN KORMA
850
1
And the result I want is but don't get it on adding Date in where clause :
Item
Amount
Qty
KOFTA ANDA
1950
3
HOT N SOUR SOUP
550
1
CHICKEN CHOWMEIN
250
1
CHICKEN KORMA
850
1
CRISPY CHICKEN
0
0
MEXICAN BURGER
0
0
What if you don't put criteria for Invoices in the WHERE clause?
Sample data
create table Categories (
Id int primary key,
Name varchar(30) not null,
TerminalId int not null
);
create table MenuItems (
Id int identity(21,1) primary key,
Name varchar(30) not null,
CategoryId int not null,
foreign key (CategoryId) references Categories(Id)
);
create table Invoices (
Id int identity(31,1) primary key,
TerminalId int not null,
ItemId int not null,
Time datetime,
foreign key (ItemId) references MenuItems(Id)
);
create table InvoiceDetails (
InvoiceDetailId int identity(41,1) primary key,
InvoiceId int,
Amount decimal(10,2),
Qty int,
foreign key (InvoiceId) references Invoices(Id)
);
insert into Categories (Id, Name, TerminalId) values
(1,'KOFTA', 1),
(2,'SOUP', 1),
(3,'CHICKEN', 1),
(4,'BURGER', 1);
insert into MenuItems (CategoryId, Name) values
(1,'KOFTA ANDA'),
(2,'HOT N SOUR SOUP'),
(3,'CHICKEN CHOWMEIN'),
(3,'CHICKEN KORMA'),
(3,'CRISPY CHICKEN'),
(4,'MEXICAN BURGER');
insert into Invoices (ItemId, TerminalId, Time)
select itm.Id, cat.TerminalId, GetDate() as Time
from MenuItems itm
join Categories cat on cat.Id = itm.CategoryId
where itm.Name in (
'KOFTA ANDA',
'HOT N SOUR SOUP',
'CHICKEN CHOWMEIN',
'CHICKEN KORMA'
);
insert into InvoiceDetails (InvoiceId, Amount, Qty) values
(31, 1950, 3),
(32, 550, 1),
(33, 250, 1),
(34, 850, 1);
Query
DECLARE #TerminalId INT = 1;
DECLARE #Date DATE = GetDate();
SELECT
V.[Date],
C.Name AS Category,
M.Name AS MenuItemName,
ISNULL(SUM(D.Amount), 0) AS Amount,
ISNULL(SUM(D.Qty), 0) AS Qty
FROM Categories AS C
CROSS JOIN (SELECT #Date AS [Date], #TerminalId AS TerminalId) V
JOIN MenuItems AS M
ON M.CategoryId = C.Id
LEFT JOIN Invoices I
ON I.ItemId = M.Id
AND I.TerminalId = V.TerminalId
AND CAST(I.Time AS DATE) = V.[Date]
LEFT JOIN InvoiceDetails AS D
ON D.InvoiceId = I.Id
WHERE C.TerminalId = V.TerminalId
GROUP BY V.[Date], C.Id, M.Id, C.Name, M.Name
ORDER BY SUM(D.Qty) DESC
Date
Category
MenuItemName
Amount
Qty
2021-12-18
KOFTA
KOFTA ANDA
1950.00
3
2021-12-18
SOUP
HOT N SOUR SOUP
550.00
1
2021-12-18
CHICKEN
CHICKEN CHOWMEIN
250.00
1
2021-12-18
CHICKEN
CHICKEN KORMA
850.00
1
2021-12-18
CHICKEN
CRISPY CHICKEN
0.00
0
2021-12-18
BURGER
MEXICAN BURGER
0.00
0
Demo on db<>fiddle here
Here's my crack at your goal. Notice the changes. I found the reference to TerminalId in Category table highly suspicious - so much that I suspect it is a model flaw. Along those lines I note that TerminalId should likely have a foreign key to a missing table for Terminals. So I ignore that.
With that out, references to Category are now irrelevant. So that was removed as well. I also changed the procedure name since I find the reference to "day" misleading. It is highly likely "menu performance" would be evaluated on a "day" basis since retail (especially food service) sales vary by day of week consistently. So let's not mislead anyone thinking that is what this procedure does.
For simplicity and clarity, I removed the ISNULL usage. Add it back if desired but such things are usually better handled by the consumer of the resultset. I left the ORDER BY clause as a stub for you to re-evaluate (and you need to).
So how does this work? Simply calculate the sums directly in the CTE and then outer join from the menu items to the CTE sums to get all menu items along with the relevant performance information for the date specified.
CREATE PROCEDURE dbo.GetMenuPerformanceByDate
#Date date,
#Terminal int
AS
BEGIN
with sales as (
select det.ItemId, SUM(det.Amount) as amt, SUM(det.Qty) as qty
from dbo.Invoices as inv
inner join dbo.InvoiceDetails as det
on inv.Id = det.InvoiceId
where cast(inv.Time as date) = #Date
and inv.TerminalId = #Terminal
group by det.ItemId
)
select menu.name, sales.amt, sales.qty
from dbo.MenuItems as menu
left join sales
on menu.Id = sles.ItemId
order by ...
;
END;
One last note. This filter:
cast(inv.Time as date) = #Date
is generally not a good method of filtering a datetime column. Far better to use inclusive lower and exclusive upper boundaries like:
inv.Time >= #date and inv.Time < dateadd(day, 1, #date)
for this reason.
My last note - there is a potential flaw regarding MenuItems. Presumably "name" is unique. It is highly unlikely that multiple rows would have the same name, but "unlikely" is not a restriction. If you generate rows based on name and name turns out to NOT be unique, your results are difficult to interpret.

SQL- Sorting marketing categories without table data

A department store uses the following table to track sales. The data model does not include information about the floor and the category of the goods been sold.
CREATE TABLE A1
(
date datetime,
category nvarchar(30),
turnover money
);
INSERT INTO A1 VALUES (SYSDATETIME(), 100, 1000);
INSERT INTO A1 VALUES (SYSDATETIME(), 201, 1700);
...
Data model/ table cannot be changed or edited. Information on the product group and floor can be diverted from the category.
CREATE VIEW sort_department_productgroups_view
AS
WITH sort_department_productgroups
AS (SELECT date,
category,
turnover,
CASE category
WHEN 100 THEN 1
WHEN 201 THEN 1
WHEN 303 THEN 1
WHEN 101 THEN 2
WHEN 102 THEN 2
ELSE 9
END
floor,
CASE category
WHEN 100 THEN 'sport'
WHEN 102 THEN 'sport'
WHEN 201 THEN 'leisure'
WHEN 303 THEN 'business'
WHEN 101 THEN 'sport'
WHEN 202 THEN 'leisure'
ELSE 'unknown'
END
productgroup
FROM a1)
SELECT *
FROM sort_department_productgroups;
go
Example query on the new view:
SELECT * FROM sort_department_productgroups_view where productgroup='sport';
Are there better ways to deal with such a task? Would this work on a big database?
This is really crying for a lookup table. But I must admit, that a category column of type nvarchar filled with numeric values makes me wonder...
Try it like this:
EDIT: Changed the related columen to NVARCHAR(30) as OP mentioned, that this is unchangeable...
CREATE TABLE CATEGORY(ID INT IDENTITY CONSTRAINT PK_CATEGORY PRIMARY KEY
,category NVARCHAR(30)
,CategoryName VARCHAR(100)
,[Floor] INT );
INSERT INTO CATEGORY VALUES
(100,'sport',1)
,(101,'sport',2)
,(102,'sport',2)
,(201,'leisure',1)
,(202,'leisure',9)
,(303,'business',9)
--add more...
CREATE TABLE A1
(
date datetime,
category NVARCHAR(30),
turnover money
);
INSERT INTO A1 VALUES (SYSDATETIME(), 100, 1000);
INSERT INTO A1 VALUES (SYSDATETIME(), 201, 1700);
GO
CREATE VIEW sort_department_productgroups_view
AS
SELECT A1.date
,a1.turnover
,ISNULL(CATEGORY.Floor,9) AS [Floor]
,ISNULL(CATEGORY.CategoryName,'unknown') AS [productgroup]
FROM A1
LEFT JOIN CATEGORY ON CATEGORY.category=A1.category;
GO
SELECT * FROM sort_department_productgroups_view
I agree with Shnugo that a reference table is much preferable.
I would define the view more simply as:
CREATE VIEW sort_department_productgroups_view AS
SELECT date, category, turnover,
(CASE WHEN category IN ('100', '201', '202') THEN 1
WHEN category IN ('101', '102') THEN 2
ELSE 9
END) as floor,
(CASE WHEN category IN ('100', '101', '102') THEN 'sport'
WHEN category IN ('201', '202') THEN 'leisure'
WHEN category IN ('303') THEN 'business'
ELSE 'unknown'
END) as productgroup
FROM a1;
Two important differences:
This no longer uses a searched case, so it keeps the definition of each group in one condition.
The values are in quotes because category is a string.
Finally, SQL Server allows computed columns, so you can incorporate this "column" into the table definition:
alter table a1
add floor as (CASE WHEN category IN ('100', '201', '202') THEN 1
WHEN category IN ('101', '102') THEN 2
ELSE 9
END);
And similarly for the product group.

SQL query giving incorrect results for average customer age

I'm not really sure whether my SQL query below is correct but let's say that there are three tables as described below:
table customer:
name
passport
age
table menu:
type
item
price
table breakfast:
passport
item
I need to find the average age of the customers who ordered fried rice for breakfast. The common field between customer and breakfast is the `passport column so my current attempt is to join using that and average the customer ages:
SELECT AVG(c.age) FROM customer c, breakfast b
WHERE c.passport = b.passport
AND b.item = 'Fried Rice';
That, however, is giving incorrect values some of the time.
Thinking it may need to use distinct values, I instead tried this but it also gave incorrect results:
Should the query below instead be:
SELECT AVG(c.age) FROM customer c
WHERE c.passport EXISTS IN (
SELECT DISTINCT b.passport FROM breakfast b
WHERE b.item = 'Fried Rice'
);
What is the problem with these, and what would be the correct query? Even pointers would help out here.
With your first query, think of what would happen if I was meeting Taylor Swift for breakfast one morning(a) but I was really hungry and decided to have two helpings?
Imagine the rows returned for that by the first query:
pax 50
pax 50
taylor 26
Clearly, the average age of pax and taylor is (50 + 26) / 2 = 38, but averaging those three rows would give you (50 + 50 + 26) / 3 = 42.
The key here is the phrase "the average age of the customers", meaning it shouldn't matter how many helpings of fried rice a person had, they're still only a single customer.
The second query is closer in that it attempts to make sure that customers are not duplicated in the results, at least once you fix the errant use of exists in as per the below commands:
create table customer(name varchar(20), passport integer, age integer);
create table breakfast(passport integer, item varchar(20));
insert into customer(name, passport, age) values ('pax', 1, 50);
insert into customer(name, passport, age) values ('taylor', 2, 26);
insert into breakfast (passport, item) values (1, 'fried rice');
insert into breakfast (passport, item) values (1, 'fried rice');
insert into breakfast (passport, item) values (2, 'fried rice');
select * from customer;
select "";
select * from breakfast;
select "";
select avg(c.age) from customer c, breakfast b
where c.passport = b.passport
and b.item = 'fried rice';
select avg(age) from customer
where passport in (
select distinct passport from breakfast
where item = 'fried rice'
);
drop table customer;
drop table breakfast;
Running that script shows the difference (annotated with #):
pax#styxbank> sqlite3 mydb.sdb < mysql.sql
pax|1|50 # These are the two customers.
taylor|2|26
1|fried rice # These are the three breakfast rows.
1|fried rice
2|fried rice
42.0 # This is based on averaging the three rows,
38.0 # whereas this is averaging the unique customers.
(a) Yeah, as if that could ever happen :-)
Your second query has the right idea as Taylor Swift's date mentioned, but it is malformed. You can use WHERE column in (list of values) or WHERE EXISTS (query or condition):
SELECT AVG(c.age)
FROM customer c
WHERE EXISTS (SELECT 1
FROM breakfast b
WHERE b.item='Fried Rice'
AND b.passport = c.passport)
;
Or:
SELECT AVG(c.age)
FROM customer c
WHERE c.passport IN (SELECT DISTINCT b.passport
FROM breakfast b
WHERE b.item='Fried Rice')
;

Applying multiple percentages to a column

I know I can use a cursor for this, but I'm trying to write this with ideally a set based solution or perhaps a CTE. I have 2 tables (simplified for post), products - each having a base price, then a table of modifiers which are percentage increases to apply in succession to that price. So if a product has 2 percentages, i.e., 4% and 5%, I can't just increase the base price by 9%, the requirement is to increase the base price by 4% then the result of that is increased by 5%. This can happen 1 to many times. Here is what I have so far:
CREATE TABLE #Product
(ProdID INT,
BasePrice MONEY)
INSERT INTO #Product
VALUES
(1, 10), (2, 20)
CREATE TABLE #Modifiers
(ProdID INT,
ModPercent INT)
INSERT INTO #Modifiers
VALUES
(1, 2), (1,5), (2, 2), (2, 3), (2,5)
The desired output for these 2 products is:
Prod 1 ((10 * 1.02) * 1.05) = 10.71
Prod 2 (((20 * 1.02) * 1.03) * 1.05) = 22.0626
I tried messing around with EXP(SUM(LOG())) in a straight query, but it seems I'm always summing the percentages. I also tried a CTE, but I can't seem to get it from infinitely recursing:
WITH ProductOutput (ProdID, SumPrice) AS
(
SELECT ProdID, BasePrice
FROM #Product
UNION ALL
SELECT P.ProdID, CAST(O.SumPrice * (1 + (M.ModPercent / 100.00)) AS MONEY)
FROM #Product P
INNER JOIN #Modifiers M ON
P.ProdID = M.ProdID
INNER JOIN ProductOutput AS O
ON P.ProdID = O.ProdID
)
SELECT ProdID, SUM(SumPrice)
FROM ProductOutput
GROUP BY ProdID
I appreciate any insights that could be offered. I would imagine this has been done before, but my searches didn't yield any hits.
select ProdId, EXP(SUM(LOG(ModPercent/100+1)))*AVG(BasePrice)
from Product
join Modifiers using(ProdId)
group by ProdId
Should do the trick
SQL 2005 added Outer Apply -- makes lots of complex SQL clearer to me -- clearly not necessary as the Group By is providing the key insight here -- but worth learning when you add conditions to the "join logic" it becomes invaluable
select P.ProdID
, ML.logmarkup
, P.BasePrice
, P.BasePrice * exp(ML.logmarkup) as NewPrice
from #Product P
outer apply
(
select sum(log(1.0+M.ModPercent/100.0)) as logmarkup
from #Modifiers M where (M.ProdID = P.ProdID)
group by M.ProdID
) ML
ProdID logmarkup BasePrice NewPrice
----------- ---------------------- --------------------- ----------------------
1 0.0685927914656118 10.00 10.71
2 0.0981515937071562 20.00 22.0626
(2 row(s) affected)

SQL query getting data

In SQL Server 2000:
hello i have a table with the following structure:
sku brand product_name inventory_count
------ ------ ------------- ---------------
c001 honda honda car 1 3
t002 honda honda truck 1 6
c003 ford ford car 1 7
t004 ford ford truck 1 8
b005 honda honda bike 5 9
b006 ford ford bike 6 18
I'm using the following SQL query
select distinct left(sku,1) from products
this would return the following:
c
t
b
and then ...
c = car
t = truck
b = bike
this works great,
Now I want to get just one product example for each of the categories with the greatest INVENTORY_COUNT
so that it returns the data as:
c, "ford car 1"
t, "ford truck 1"
b, "ford bike 6"
what SQL query would i run to get that data??
i want the item with the greatest INVENTORY_COUNT for each category.. left(sku,1)
thanks!!
You could join the table on itself to filter out the rows with less than maximum inventory:
select left(a.sku,1), max(a.product_name), max(a.inventory_count)
from YourTable a
left join YourTable more_inv
on left(a.sku,1) = left(more_inv.sku,1)
and a.inventory_count < more_inv.inventory_count
where more_inv.sku is null
group by left(a.sku,1)
The WHERE condition on more_inv.sku is null filters out rows that don't have the highest inventory for their one letter category.
Once we're down to rows with the maximum inventory, you can use max() to get the inventory_count (it'll be the same for all rows) and another max() to get one of the products with the highest inventory_count. You could use min() too.
im using the following sql query which works,
SELECT DISTINCT left(field1,1) as cat , MAX(sku) as topproduct FROM products where inventory_count > 0 GROUP BY left(sku,1)
i just need to add in there an ..order by inventory_count
Using SQL Server 2005 you can try this
DECLARe #Table TABLE(
sku VARCHAR(50),
brand VARCHAR(50),
product_name VARCHAR(50),
inventory_count INT
)
INSERT INTO #Table SELECT 'c001', 'honda', 'honda car 1', 3
INSERT INTO #Table SELECT 't002', 'honda', 'honda truck 1', 6
INSERT INTO #Table SELECT 'c003', 'ford', 'ford car 1', 7
INSERT INTO #Table SELECT 't004', 'ford', 'ford truck 1', 8
INSERT INTO #Table SELECT 'b005', 'honda', 'honda bike 5', 9
INSERT INTO #Table SELECT 'b006', 'ford', 'ford bike 6', 18
SELECT LEFT(sku,1),
product_name
FROM (
SELECT *,
ROW_NUMBER() OVER( PARTITION BY LEFT(sku,1) ORDER BY inventory_count DESC) ORDERCOUNT
FROm #Table
) SUB
WHERE ORDERCOUNT = 1
OK Then you can try
SELECT LEFT(sku,1),
*
FROm #Table t INNER JOIN
(
SELECT LEFT(sku,1) c,
MAX(inventory_count) MaxNum
FROM #Table
GROUP BY LEFT(sku,1)
) sub ON LEFT(t.sku,1) = sub.c and t.inventory_count = sub.MaxNum
For mysql:
SELECT LEFT(sku,1), product_name FROM Table1 GROUP BY LEFT(sku,1)
For MS SQL 2005 (maybe also works in 2000?):
SELECT LEFT(sku,1), MAX(product_name) FROM Table1 GROUP BY LEFT(sku,1)
Try this
declare #t table (sku varchar(50),brand varchar(50),product_name varchar(50),inventory_count int)
insert into #t
select 'c001','honda','honda car 1',3 union all
select 't002','honda','honda truck 1',6 union all
select 'c004','ford','ford car 1',7 union all
select 't004','ford','ford truck 1',8 union all
select 'b005','honda','honda bike 5',9 union all
select 'b006','ford','ford bike 6',18
Query:
select
x.s + space(2) + ',' + space(2) + '"' + t.product_name + '"' as [Output]
from #t t
inner join
(
SELECT left(sku,1) as s,MAX(inventory_count) ic from #t
group by left(sku,1)
) x
on x.ic = t.inventory_count
--order by t.inventory_count desc
Output
c , "ford car 1"
t , "ford truck 1"
b , "ford bike 6"
In general, might there not be more than one item with max(inventory_count)?
To get max inventory per cateogry, use a subquery, (syntax will depend on your database):
SELECT LEFT(sku,1) as category, MAX(inventory_count) as c
FROM Table1
GROUP BY LEFT(sku,1)
SORT BY LEFT(sku,1)
This will give you a table of max_inventory by category, thus:
b,18
c,7
t,8
So now you know the max per category. To get matching products, use this result as
a subquery and find all products in the given cateogry that match the given max(inventory_count):
SELECT t1.*
FROM Table1 AS t1,
(SELECT LEFT(sku,1) AS category, MAX(inventory_count) AS c
FROM Table1
GROUP BY LEFT(sku,1)
) AS t2
WHERE LEFT(t1.sku,1) = t2.category AND t2.c = t1.inventory_count
Sorry, the code above may/may not work in your database, but hope you get the idea.
Bill
PS -- probably not helpful, but the table design isn't really helping you here. If you have control over the schema, would help to separate this into multiple tables.