I want to remove the need for a nested query if I can from my query below, but I'm struggling to work out how.
This is the schema:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[expiration]
(
[batch_number] [int] NOT NULL,
[fruit_number] [int] NOT NULL,
[store_number] [int] NOT NULL,
[expiration_date] [date] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[fruits]
(
[fruit_number] [int] NOT NULL,
[fruit_name] [nvarchar](50) NOT NULL
) ON [PRIMARY]
This is the data:
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (1, 3, 4, CAST(N'2021-11-25' AS Date))
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (1, 2, 2, CAST(N'2021-11-22' AS Date))
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (1, 5, 3, CAST(N'2021-11-30' AS Date))
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (2, 2, 7, NULL)
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (2, 3, 2, CAST(N'2021-12-12' AS Date))
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (1, 1, 5, NULL)
INSERT INTO [dbo].[expiration] ([batch_number], [fruit_number], [store_number], [expiration_date])
VALUES (2, 1, 6, CAST(N'2021-11-28' AS Date))
INSERT INTO [dbo].[fruits] ([fruit_number], [fruit_name])
VALUES (1, N'banana')
INSERT INTO [dbo].[fruits] ([fruit_number], [fruit_name])
VALUES (2, N'apple')
INSERT INTO [dbo].[fruits] ([fruit_number], [fruit_name])
VALUES (3, N'pear')
INSERT INTO [dbo].[fruits] ([fruit_number], [fruit_name])
VALUES (4, N'peach')
INSERT INTO [dbo].[fruits] ([fruit_number], [fruit_name])
VALUES (5, N'strawberry')
And this is my query:
SELECT
fruit_number,
MAX(expirationDate) as expirationDate
FROM
(SELECT
f.fruit_number,
CASE
WHEN e.expiration_date is NULL AND e.fruit_number IS NOT NULL THEN 1
ELSE 0
END AS expirationDate
FROM
expiration AS e
FULL OUTER JOIN
fruits AS f ON f.fruit_number = e.fruit_number
WHERE
f.fruit_number IS NOT NULL) t
GROUP BY
fruit_number
ORDER BY
fruit_number
It produces this result set:
fruit_number | expirationDate |
---|---|
1 | 1 |
2 | 1 |
3 | 0 |
4 | 0 |
5 | 0 |
The resultset is what I'm after, but it's ugly having the nested query. Is it possible to do this without the nested query? An online query analyser (https://www.eversql.com/sql-query-optimizer/) said to move the sub-query into a temp table and query against that, but isn't just doing the same thing in more steps?
CodePudding user response:
Give this a try, I believe it gets you what you wanted:
SELECT t1.fruit_number
, CASE WHEN MIN(ISNULL(expiration_date, '1/1/1900')) = CAST('1/1/1900' as date) and t2.fruit_number IS NOT NULL THEN 1 ELSE 0 END expirationDate
FROM fruits t1
LEFT JOIN expiration t2 on t1.fruit_number = t2.fruit_number
GROUP BY t1.fruit_number, t2.fruit_number
ORDER BY t1.fruit_number
CodePudding user response:
The first change I would make is with your joins. It makes no sense to use a FULL OUTER JOIN
then put in a where clause that says f.fruit_number IS NOT NULL
. This means that every row must have a record in fruits
, so your query would make more sense as SELECT .. FROM fruits AS f LEFT JOIN expiration AS e ON e.fruit_number = f.fruit_number
.
You can also remove the subquery by placing your case expression directly within the MAX
function:
SELECT f.fruit_number,
f.fruit_name,
expirationDate = MAX(CASE WHEN e.expiration_date IS NULL
AND e.fruit_number IS NOT NULL THEN 1 ELSE 0 END)
FROM dbo.fruits AS f
LEFT JOIN dbo.expiration AS e
ON e.fruit_number = f.fruit_number
GROUP BY f.fruit_number, f.fruit_name
ORDER BY f.fruit_number;