Reputation: 929
I have a database with 5 columns (A1,A2,A3,A4,A5
) which store 5 numbers.
The 5 numbers are "1,2,3,4,5"
.
A1 A2 A3 A4 A5
-------------------------------
2 4 5 Null Null
I want get the missing number which is "1" and "3". How do I find the missing number from 5 numbers?
Upvotes: 0
Views: 318
Reputation: 3472
An elegant solution that is extensible beyond the 5 values presented in your question makes use of a numbers table (as shown in the link, a numbers table is invaluable for a multitude of tasks).
Here's the setup for the numbers table, which in this case is limited to 256 numbers since you're using a small range in the question.
/*
create a numbers table with numbers from 0 to
255 (the range of the tinyint data type).
*/
DROP TABLE IF EXISTS [#numbers];
GO
CREATE TABLE [#numbers]
(
[n] tinyint NOT NULL
);
WITH [numbers]
AS
(
SELECT [v].[n]
FROM
(
VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)
) [v]([n])
)
INSERT INTO [#numbers]
(
[n]
)
SELECT TOP(255)
[number] =
([n1].[n] * 100)
+ ([n2].[n] * 10)
+ ([n3].[n] * 1)
FROM
[numbers] [n1]
CROSS JOIN [numbers] [n2]
CROSS JOIN [numbers] [n3]
ORDER BY
([n1].[n] * 100)
+ ([n2].[n] * 10)
+ ([n3].[n] * 1);
Next, we'll create the table you mention in your question:
DROP TABLE IF EXISTS [#rows];
CREATE TABLE [#rows]
(
[a1] tinyint NULL
, [a2] tinyint NULL
, [a3] tinyint NULL
, [a4] tinyint NULL
, [a5] tinyint NULL
);
Here, we populate the row with your values:
INSERT INTO [#rows] ([a1], [a2], [a3])
VALUES (2, 4, 5);
The contents of the [#rows]
table:
a1 | a2 | a3 | a4 | a5 |
---|---|---|---|---|
2 | 4 | 5 | NULL | NULL |
I'm going to use an UNPIVOT clause to turn columns into rows. For clarity, this is what the UNPIVOT
looks like on its own:
SELECT
[upv].[value]
FROM
(
SELECT *
FROM [#rows]
) [src]
UNPIVOT
(
[value] FOR [column] IN ([a1], [a2], [a3], [a4], [a5])
) [upv]
ORDER BY
[upv].[value];
The intermediate results of the UNPIVOT
query:
value |
---|
2 |
4 |
5 |
As you can see, we're missing the values 1
and 3
. Here's where we display the missing values by combining the results of the UNPIVOT
with an EXCEPT T-SQL operator against the [#numbers]
table to show the missing values:
SELECT
[missing_number] = [n].[n]
FROM
[#numbers] [n]
WHERE
[n].[n] > 0
AND [n].[n] <= 5
EXCEPT
SELECT
[upv].[value]
FROM
(
SELECT *
FROM [#rows]
) [src]
UNPIVOT
(
[value] FOR [column] IN ([a1], [a2], [a3], [a4], [a5])
) [upv];
The EXCEPT
operator shows distinct results from the left side of the operator that do not exist in the results from the right side of the operator. The results are:
missing_number |
---|
1 |
3 |
Upvotes: 1
Reputation: 92785
You can do this
WITH sequence AS
(
SELECT 1 n UNION ALL
SELECT n + 1 FROM sequence WHERE n < 5
)
SELECT n
FROM sequence s LEFT JOIN table1 t
ON s.n IN (t.a1, t.a2, t.a3, t.a4, t.a5)
WHERE t.a1 IS NULL
Output:
| N | |---| | 1 | | 3 |
Here is SQLFiddle demo
Upvotes: 2
Reputation: 2006
you'll need a table of integers from 1 to (in this case) 5:
DECLARE @ints table (n int);
INSERT @ints VALUES (1), (2), (3), (4), (5);
second, we get the numbers in the table row into a single comparable set:
SELECT x INTO #all FROM (
SELECT A1 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A2 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A3 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A4 as x FROM myTable WHERE ID = myRow
UNION ALL
SELECT A5 as x FROM myTable WHERE ID = myRow
) y
then you can derive the answer:
SELECT @ints.n
FROM @ints left join #all on @ints.n = #all.x
WHERE #all.x is null
ORDER BY 1
Upvotes: 0
Reputation: 8109
Select Replace(Replace(Replace(Replace(
Replace('12345',(Cast(Coalesce(A5,0) as varchar(1))),''),
(Cast(Coalesce(A4,0) as varchar(1))),''),
(Cast(Coalesce(A3,0) as varchar(1))),''),
(Cast(Coalesce(A2,0) as varchar(1))),''),
(Cast(Coalesce(A1,0) as varchar(1))),'') from Table1
Upvotes: 2