Check existence of a result from sub query in SELECT - sql

How do I get not-null results from a sub query in SELECT statement?
SELECT a, b, c,
(SELECT d
FROM table2
WHERE ...) as d
FROM table 1
WHERE ...
I want to get results only when all values (a, b, c , d) not Null.
It won't be kind of weird/non-efficient to use the same sub-query in main WHERE clause as well but with EXISTS?

The easiest way to do this is to put your original query in a subquery, then you can check whether the whole row that the subquery returns is NULL:
SELECT *
FROM (
SELECT a, b, c,
(SELECT d
FROM table2
WHERE ...)
FROM table 1
WHERE ...
) AS sub
WHERE sub IS NOT NULL
sub being the row of (a,b,c,d) returned by the subquery.

You can use a subquery:
select a, b, c, d
from (SELECT a, b, c,
(SELECT d
FROM table2
WHERE ...) as d
FROM table 1
WHERE ... and
a is not null and b is not null and c is not null
) x
where d is not null;
In all likelihood, though, you can use JOIN:
SELECT a, b, c, x.d
FROM table 1 JOIN
(SELECT d
FROM table2
WHERE ...
) x
WHERE ... and
a is not null and b is not null and c is not null and d is not null;

SELECT
t1.a,
t1.b,
t1.c,
t2.d
FROM table1 t1
left join table2 as t2 on t2.ID = t1.ID
WHERE t1.a is not null and t1.b is not null and t1.c is not null and t2.d is not null

Related

SQL - Select using attributes from two tables

I am having an issue in extracting data using data of two tables in SQL.
select A, B, C, D
from Table_one T1
where A in (select T2.A from Table_two T2
where T2.E <> 'ZZZ');
This returns A, B, C, D where E in T2 is not ZZZ.
However, when I add another where clause like below,
it returns data where T2 is ZZZ also.
select A, B, C, D
from Table_one T1
where A in (select T2.A from Table_two T2
where T2.E <> 'ZZZ')
and D <> 0 ;
This ignores "T2.E <> 'ZZZ'" part, but "D<>0" is not ignored.
Why is this happening?
Because you have duplicates in Table_two. For some of those duplicates, one has the value of ZZZ and the other does not.
You are using the wrong logic if you want to exclude rows that have a ZZZ in table_two. I would recommend NOT EXISTS:
select A, B, C, D
from Table_one T1
where not exists (select 1
from Table_two T2
where T1.A = T2.A and
T2.E = 'ZZZ'
) and
D <> 0 ;

Update Fields - SQL Server

In SQL Server, I am trying to update null fields in a table with existing vales in the table.
Example:
Table has 4 columns:A,B,C,D
A B C D
1 2 3 4
5 Null Null 4
How can I populate the Null values with the values in B,C where D=4
Update Table
Set B=B
Where B is null
and D=4
One option is to use a self join:
update t
set t.b = t2.b
from yourtable t
join yourtable t2 on t.d = t2.d
and t2.b is not null
where t.b is null
What if multiple records exist for b grouped by d where b is not null? That could mess this up. Instead you'd have to decide which value to use. Here's an example choosing the min:
update t
set t.b = t2.b
from yourtable t
join (select d, min(b) b
from yourtable
where b is not null
group by d) t2 on t.d = t2.d
where t.b is null
Or with a correlated subquery:
update yourtable t
set b = (select min(b) from yourtable t2 where t.id = t2.id)
where t.b is null
A lot of options here...

most recent (max) date for every id

a = id
b = date
c = NewestDate
For every a, I have b c
How can I get the newest date for every set of id's (MY 'a' column)? they don't all have the same end date. So I do need a max for all of them.
The data is in myTable,
so far i tried:
select *
into #myTable
from myTable
select
t.a
,t.b
,t.c
,(select max(b) from myTable) as c
from myTable t
left join #myTable t1
on t.a = t1.a and t.b = t1.b
order by a, b
The problem with the above code is that in 'c' it is placed the max date of them all, which is not what I actually want.
EDIT: the problem is now solved with the answer given by Dmitry Poliakov (thanks). Used:
SELECT a,
b,
max(b) OVER (PARTITION BY a) AS c
FROM myTable
ORDER BY a,b
you can select maximum date for each group of ids as
SELECT a,
b,
max(b) OVER (PARTITION BY a) AS c
FROM myTable
ORDER BY a,b
EDIT: one of possible solutions for the second(edited) part of question is
WITH cte AS (
SELECT a,
b,
max(b) OVER (PARTITION BY a) AS c,
d
FROM myTable
)
SELECT t1.a,
t1.b,
t1.c,
t1.d,
t2.d AS e
FROM cte t1
JOIN cte t2 ON t1.a=t2.a AND t1.c=t2.b
DECLARE #updates TABLE (a int,b date,c date)
INSERT INTO #updates VALUES
(1,GETDATE(),GETDATE()+10),
(2,GETDATE()+11,GETDATE()+13),
(2,GETDATE()+11,GETDATE()+14),
(3,GETDATE()+11,GETDATE()+13),
(1,GETDATE()+11,GETDATE()+13);
WITH
cte AS
(
SELECT a, max(c) latest
FROM #updates
GROUP BY a
)
SELECT *
FROM cte INNER JOIN #updates as d ON cte.a=d.a AND cte.latest = d.c
Builds a table to select the records with the newest updates and then joins this new table with your original table to extract all the fields in matching rows

How to restructure SQL query so that I can write/refer them easily

I have following queries.
Select * from (
Select a, b, c, d, from t1
Union
Select a, b, c, d from t2
) where a is not null and order by b.
Now I have to fetch data from another table based on above result set.
Select * from (Select * from (
Select a, b, c, d, from t1
Union
Select a, b, c, d from t2
)
where a is not null and order by b)
as tempT1 left outer join t3 on tempT1.a = t3.a
I have to further use this result set to form another select query. So, writing in above style will be complex with time. And with time this query will be complex to read.
How to make it simple? Can I dump partial result to another table?
You can create views that will replace these inner SELECTs
From w3schools :
"In SQL, a view is a virtual table based on the result-set of an SQL statement.
A view contains rows and columns, just like a real table. The fields in a view are fields from one or more real tables in the database.
You can add SQL functions, WHERE, and JOIN statements to a view and present the data as if the data were coming from one single table."
Document them so you wont get lost and that's it...
Use temporary tables. Rewrite your queries as
Select * into #tempResult1 from (
Select a, b, c, d, from t1
Union
Select a, b, c, d from t2
) where a is not null and order by b
Now for next query, use above temp table as
Select * into #tempResult2
from #tempResult1
left outer join t3 on tempT1.a = t3.a
Now instead of writing this query, just use #tempResult2.
select * from #tempResult2
You have some wrong SQL syntax too. Try:
;
WITH Q1
AS ( SELECT a ,
b ,
c ,
d
FROM t1
UNION
SELECT a ,
b ,
c ,
d
FROM t2
),
Q2
AS ( SELECT *
FROM Q1
)
SELECT *
FROM Q2 tempT1
LEFT OUTER JOIN t3 ON tempT1.a = t3.a
WHERE a IS NOT NULL
ORDER BY b
Assuming that you are using SQL Server, You could simplify something like below. Not a compiled version. But you could use this as pseudo code.
with cte as
(
Select a, b, c, d from t1 where a is not null
Union
Select a, b, c, d from t2 where a is not null
)
select * from cte tempT1 left outer join t3 on tempT1.a = t3.a order by tempT1.b
You Can use Comman Table expression or Temp Table or Table Variable
with cte as
(
Select a, b, c, d from t1
Union
Select a, b, c, d from t2
)
,
cte2 as
(
select * cte where a is not null and order by b
)
select * from cte2 c left outer join t3 on c.a = t3.a
Using Temp Table
select * into #temp1
from
(
Select a, b, c, d from t1
Union
Select a, b, c, d from t2
)
select * into #temp2 from #temp1 where a is not null and order by b
select * from temp2 c left outer join t3 on c.a = t3.a

Oracle subquery top 1 result

I want to get the top 1 row for each unique value of b with the minimum value of c for that particular value of b. Even though there can be more than 1 row with the same min value (just chose the first one)
myTable
a integer (unique)
b integer
c integer
I've tried this query
SELECT t1.*
FROM myTable t1,
(SELECT b,
MIN(c) as c
FROM myTable
GROUP BY b) t2
WHERE t1.b = t2.b
AND t1.c = t2.c
However, in this table it's possible for there to be more than 1 instance of the minimum value of c for a given value of b. The above query generates duplicates under these conditions.
I've got a feeling that I need to use rownum somewhere, but I'm not quite sure where.
You can use ROW_NUMBER:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY b ORDER BY c) AS rn
FROM myTable
) AS T1
WHERE rn = 1
To tie-break between the equal c's, you will need to subquery one level further to get the min-a for each group of equal c's per b. (A mouthful!)
select t0.*
FROM myTable t0
inner join (
select t1.b, t1.c, MIN(a) as a
from myTable t1
inner join (
select b, min(c) as c
from myTable
group by b
) t2 on t1.b = t2.b and t1.c = t2.c
group by t1.b, t1.c
) t3 on t3.a = t0.a and t3.b = t0.b and t3.c = t0.c