I want to identify in one column those who are present in the data but there is limit to only 10 nests. Is there easier or some other way for me to get the result that I want?
I hope you could help me.
Best Answer
You can do that using a CASE expression:
select a,b,c,d,
case (a + b * 2 + c * 4 + d * 8)
when 0 then 'none'
when 1 then 'a'
when 2 then 'b'
when 4 then 'c'
when 8 then 'd'
when 3 then 'a-b'
when 7 then 'a-b-c'
when 5 then 'a-c'
when 9 then 'a-d'
when 6 then 'b-c'
when 10 then 'b-d'
when 14 then 'b-c-d'
when 12 then 'c-d'
when 15 then 'a-b-c-d'
else 'error'
end as present
from the_table;
This creates a "bitset" with one bit for each column, then tests for the values that uniquely identify each combination.
This assumes that there are no NULL values in those columns.
select concat(case when a = 1 then 'a-' end,
case when b = 1 then 'b-' end,
case when c = 1 then 'c-' end,
case when d = 1 then 'd-' end)
from the_table;
That leaves an ugly dangling - at the end, but you could probably remove that with a combination of substring() and/or replace() calls.
I don't know all of your source data (or why there isn't any type of unique constraint that would prevent full-on duplicates or a source with multiple destinations), but given only the sample data supplied:
;WITH s AS
(
-- first let's eliminate duplicates
SELECT DISTINCT Source, Destination
FROM dbo.MyTable
)
SELECT Source, Destination
FROM s
WHERE NOT EXISTS
(
SELECT 1 FROM s AS d WHERE
-- eliminate chains in either direction:
d.Destination = s.Source OR d.Source = s.Destination
-- eliminate any source with multiple destinations:
OR (d.Source = s.Source AND d.Destination <> s.Destination)
-- eliminate any destination with more than one source
OR (d.Destination = s.Destination AND d.Source <> s.Source)
);
Just Join the table to itself and make the appropriate sum.
This query will match each row in the table to all rows in the table with a smaller ID and the same category. You can then easily sum these rows and filter out all rows with a total greater than your limit.
Using sub queries in the where clause like you do might result in many unnecessary query executions if your sub-queries are not optimized to an INNER JOIN by the database engine:
DECLARE @Limit FLOAT
SELECT @Limit = 30
SELECT
o1.Id
, o1.Cost
, o1.Category
FROM
MyOrders o1
-- Join all orders with same category and inferior ID
INNER JOIN MyOrders o2 ON o2.ID <= o1.ID AND o1.Category = o2.Category
GROUP BY
o1.Id
, o1.Cost
, o1.Category
HAVING
SUM(o2.Cost) < @Limit
ORDER BY
ID
Best Answer
You can do that using a CASE expression:
This creates a "bitset" with one bit for each column, then tests for the values that uniquely identify each combination.
This assumes that there are no
NULL
values in those columns.Online example on db<>fiddle
Another option might be to concat expressions:
That leaves an ugly dangling
-
at the end, but you could probably remove that with a combination ofsubstring()
and/orreplace()
calls.