Multiple columns return in CASE Statement SQL - sql

I have two tables and based on the sum of a field in TABLE1 I have to return different datasets from TABLE2:
I am trying to achieve this through a Case statement but getting an error saying subselect must have only one field.
Is there a better way to do this? simply when the sum of a column in table1 is 0 do not select anything from table2
TABLE1:
TABLE2:
MY SQL:
SELECT
CASE
WHEN SUM(transaction_unit_failed) > 0
THEN (
SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
)
WHEN SUM(transaction_unit_failed) = 0
THEN (
SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
WHERE 1 = 2
)
FROM TABLE1

select * from table2
where exists (
select 1
from table1
having sum(transaction_unit_failed) > 0
);
Similarly:
select * from table2
where (
select sum(transaction_unit_failed)
from table1
) > 0;
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=3f68d250bc9a3235767b86626092799e
You could certainly write it as a join if there were a compelling reason. It would eliminate the convenience of nicely using * to return only the columns from the one table.
select *
from table2 inner join (
select sum(transaction_unit_failed) as stuf
from table1
) on stuf > 0;

SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
WHERE (SELECT SUM(transaction_unit_failed) > 0
FROM TABLE1)

Related

Checking whether two tables have identical content

How can I check and store in variable whether two tables have identical content?
I have table variable with data like
declare #table1 table (id int)
insert into #table1 (id) values (1), (2), (3)
and as the second table I have query
select T.id from SomeTable T
inner join #table1 T1 on T.id = T1.id
the query returns data:
id
-----
1
2
In this case I need write false(0) into declare #HasAccess BIT variable.
When the query returns data:
id
-----
1
2
3
then I need write true(1) into #HasAccess
Hmmm. There are various ways.
Given that you have one column, you can do:
select (case when count(*) = 0 then 1 else 0 end)
from t1 full join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
This checks if an id doesn't match in either table.
Another way uses union all:
select (case when count(*) = 0 then 1 else 0 end)
from (select id, sum(in_t1) as num_t1, sum(in_t2) as num_t2)
from ((select id, 1 as in_t1, 0 as in_t2 from table1) union all
(select id, 0, 1 from table2)
) tt
group by id
) tt
where num_t1 <> 1 or num_t2 <> 1;
Another option (just for fun). This will compare the entire table fields and values.
I suspect not the best option for LARGE tables
Example
Select IsIdentical = case when (Select * from Table1 Order by id For XML Raw)
= (Select * from Table2 Order by id For XML Raw)
then 1 else 0 end
EDIT - Option with Inner Join
Select IsIdentical = case when (Select * from #Table1 Order by id For XML Raw)
= (Select A.*
From SomeTable A
Join #Table1 B on A.ID=B.ID
Order By id For XML Raw)
then 1 else 0 end
Using EXCEPT:
SET #HasAccess = ISNULL(
( SELECT 0
WHERE EXISTS(
SELECT ID /* add more columns here if needed */
FROM #table1
EXCEPT
SELECT ID /* add more columns here if needed */
FROM SomeTable )), 1 )
Explanation:
Return all IDs from #table1, except those found in SomeTable
Return 0 (false) if any records have been returned by [1].
If no records returned by [1] the main query will return NULL, hence the ISNULL
Advanatages
Can easily be extended to comparisons on more than one column.

Setting a column value in the SELECT Statement based on a value existing in another table

I have 2 tables. One table lists all the records of items we track. The other table contains flags of attributes of the records in the first table.
For example, Table 1 has columns
Tab1ID, Name, Address, Phone
Table 2 has these columns
Tab2ID, Tab1ID, FlagName
There is a 1 to Many relationship between Table1 and Table2 linked by Tab1ID.
I'd like to create a query that has all the records from Table1 in it. However, if one of the records in Table2 has a Flagname=Retired (with a matching Tab1ID) then I want a "Y" to show up in the select column list otherwise an "N".
I think it might look something like this:
Select Name, Address, Phone, (select something in table2)
from Table1
where Tab1ID > 1;
It's the subquery in the column that has me stumped.
Pat
You can use exists:
Select t1.*,
(case when exists (select 1
from table2 t2
where t2.tab1id = t1.tab1id and t2.flagname = 'Retired'
)
then 'Y' else 'N'
end) as retired_flag
from Table1 t1;
I would do a normal join returning multiple records, but convert them to bits with case statements. Then use that as the subquery and pull the max value for each bit column.
select
name
,address
,phone
,max(retired_flag)
from (
select
table1.name
,table1.address
,table1.phone
,case when table2.flagname = 'retired' then 1 else 0 end as [retired_flag]
from table1
left join table2
on table1.tab1id = table2.tab1id
where tab1id > 1
) tbl
group by
name
,address
,phone

Querying two tables to filter data using select case

I have two tables
Table 1 looks like this
ID Repeats
-----------
A 1
A 1
A 0
B 2
B 2
C 2
D 1
Table 2 looks like this
ID values
-----------
A 100
B 200
C 100
D 300
Using a view I need a result like this
ID values Repeats
-------------------
A 100 NA
B 200 2
C 100 2
D 300 1
that means, I want unique ID, its values and Repeats. Repeats value should display NA when there are multiple values against single ID and it should display the Repeats value in case there is single value for repeats.
Initially I needed to display the max value of repeats so I tried the following view
ALTER VIEW [dbo].[BookingView1]
AS
SELECT bv.*, bd2.Repeats FROM Table1 bv
JOIN
(
SELECT distinct bd.id, bd.Repeats FROM table2 bd
JOIN
(
SELECT Id, MAX(Repeats) AS MaxRepeatCount
FROM table2
GROUP BY Id
) bd1
ON bd.Id = bd1.Id
AND bd.Repeats = bd1.MaxRepeatCount
) bd2
ON bv.Id = bd2.Id;
and this returns the correct result but when trying to implement the CASE it fails to return unique ID results. Please help!!
One method uses outer apply:
select t2.*, t1.repeats
from table2 t2 outer apply
(select (case when max(repeats) = min(repeats) then max(repeats)
else 'NA'
end) as repeats
from table1 t1
where t1.id = t2.id
) t1;
Two notes:
This assumes that repeats is a string. If it is a number, you need to cast it to a string.
repeats is not null.
For the sake of completeness, I'm including another approach that will work if repeats is NULL. However, Gordon's answer has a much simpler query plan and should be preferred.
Option 1 (Works with NULLs):
SELECT
t1.ID, t2.[Values],
CASE
WHEN COUNT(*) > 1 THEN 'NA'
ELSE CAST(MAX(Repeats) AS VARCHAR(2))
END Repeats
FROM (
SELECT DISTINCT t1.ID, t1.Repeats
FROM #table1 t1
) t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values]
Option 2 (does not contain explicit subqueries, but does not work with NULLs):
SELECT DISTINCT
t1.ID,
t2.[Values],
CASE
WHEN COUNT(t1.Repeats) OVER (PARTITION BY COUNT(DISTINCT t1.Repeats), t1.ID) > 1 THEN 'NA'
ELSE CAST(t1.Repeats AS VARCHAR(2))
END Repeats
FROM #table1 t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values], t1.Repeats
NOTE:
This may not give desired results if table2 has different values for the same ID.

SQL Server - Conditional OUTER APPLY

Is there a way in SQL Server 2008 do to something like below?
Can the outer applied(joined) table to be specified based on a condition?
declare #bGetExtendedInfo bit
set #bGetExtendedInfo = 1
declare #param nvarchar(24)
set #param = 'CO-02-BBB'
select t1.*, t2.ID
from t1
outer apply (
case when #bGetExtendedInfo= 0
then (select 0) as ID /* dummy value */
/*really expensive query trying to avoid when extended info is not needed*/
else (select top 1 ID from tbl1 where tbl1.code = #param)
end
) t2
You can readily do this with just a join:
SELECT t1.*, t2.*
FROM t1 cross join
(SELECT *
FROM (SELECT top 1 tb10.*, 0 as bCcond src FROM tb10
UNION ALL
SELECT top 1 tb11.*, 1 as bCcond src FROM tb11
) t
WHERE #bCond = bCcond
) t2
Doing the top before the union all should also help the optimizer produce a better query plan, in the event that the tables are really complex joins.
Also, doing top without an order by is generally frowned upon. It can return different rows with different invocations, but the rows are not guaranteed to be random.
Give this a try,
DECLARE #bCond BIT
SET #bCond = 1
SELECT t1.*, t2.*
FROM t1 OUTER APPLY
(
SELECT TOP 1 *
FROM
(
SELECT *, 'a' src FROM tb10
UNION ALL
SELECT *, 'b' src FROM tb11
)s
WHERE src = CASE WHEN #bCond = 0 THEN 'a' ELSE 'b' END
) t2

How to do a Select in a Select

I have a table containing a unique ID field. Another field (REF) contains a reference to another dataset's ID field.
Now I have to select all datasets where REF points to a dataset that doesn't exist.
SELECT * FROM table WHERE ("no dataset with ID=REF exists")
How can I do this?
3 ways
SELECT * FROM YourTable y WHERE NOT EXISTS
(SELECT * FROM OtherTable o WHERE y.Ref = o.Ref)
SELECT * FROM YourTable WHERE Ref NOT IN
(SELECT Ref FROM OtherTable WHERE Ref IS NOT NULL)
SELECT y.* FROM YourTable y
LEFT OUTER JOIN OtherTable o ON y.Ref = o.Ref
WHERE o.Ref IS NULL
See also Five ways to return all rows from one table which are not in another table
Try this:
SELECT * FROM TABLE WHERE NOT EXISTS
(SELECT * FROM OtherTable WHERE TABLE.Ref = OtherTable.ID)
I think this should work
SELECT * FROM table WHERE id NOT IN (SELECT ref_id FROM ref_table)
or with JOIN
SELECT table.*
FROM table LEFT JOIN ref_table ON table.id = ref_table.ref_id
WHERE ref_table.ref_id IS NULL
SELECT
table1.*
FROM
table1
LEFT JOIN table2 ON table1.id = table2.ref
WHERE
table2.ref IS NULL
You can do a subquery like:
select * from table where somefield not in (select otherfield from sometable where ID=REF)
SELECT *
FROM table
WHERE ((SELECT COUNT(*) FROM table2 WHERE table2.id = table.ref) = 0)
Something like that :
SELECT * FROM table WHERE ID NOT IN(SELECT REF FROM Table2 )
Yes you can use
select * from x where not exist ( select * from y )