How to SELECT WHERE EXISTS in multi table? - sql

I have 3 tables:
/test/table1:
Columns: doc_id, anotherID, value1
/test/table2:
Columns: anotherID, value1
/test/table3
Columns: doc_id, value2
I want to select the data of /test/table1 with 2 conditions. One condition in /test/table2 and another one in /test/table3.
So I select my data in one table with one condition like that:
SELECT doc_id, anotherID FROM /test/table1 AS d
INTO CORRESPONDING FIELDS OF TABLE #ct_document
WHERE EXISTS ( SELECT * FROM /test/table2 AS a
WHERE value1 < #iv_value1 AND a~value1 = d~value1_id ).
It selects the content as I expect. But now I want to add a condition, to only select this data but only where /test/table3~value2 = 2.
To do that, I do:
SELECT doc_id, anotherID FROM /test/table1 AS d
INTO CORRESPONDING FIELDS OF TABLE #ct_document
WHERE EXISTS ( SELECT * FROM /test/table2 AS a
WHERE value1 < #iv_value1 AND a~value1 = d~value1_id )
AND EXISTS ( SELECT * FROM /test/table3 AS e
WHERE e~value2 = 2 ).
When I do that, I have the same content as before... It doesn't take my second condition.
What don't I understand ?

The condition EXISTS ( SELECT * FROM /test/table3 AS e WHERE e~value2 = 2 ) is always evaluated to TRUE if there's at least one line in /test/table3 with e~value2 = 2, whatever the content of the table /test/table1.
To make it evaluated to TRUE or FALSE according to /test/table1 (alias d), you should add the condition AND e~doc_id = d~doc_id, like this:
...
AND EXISTS ( SELECT * FROM /test/table3 AS e
WHERE e~value2 = 2 AND e~doc_id = d~doc_id ).

Related

How do I return the count for both matching column in a single return

I'm trying to get a number of count for exist and non-exist for my validation to insert my data. As refer to the image below, I'm inserting 3 data in which 1 data consist of same ID number as destination table, 1 data consist of same quotation number as destination table and the last data is a new entry.
Okay here's my requirement. I am sending my source table data to insert into the dest table. So before inserting, I want to do validation by mapping the entire dest table like this:
SELECT COUNT(*) FROM sourceTable WHERE exists(
SELECT * FROM sourceTable WHERE QuotationId IN
(SELECT A.QuotationId FROM sourceTable A
JOIN DestTable B ON A.QuotationId = B.QuotationId
JOIN DestTable C ON A.QuotationNum = C.QuotationNum)
Without further details on table structure and so on it's difficult to tell, but something like the following might do the trick:
WITH cteMatch AS(
SELECT s.QuotationID AS src, d.QuotationID as dst
FROM sourceTable s
LEFT JOIN destTable d
)
SELECT CASE WHEN dst IS NULL THEN N'NonExist' ELSE N'Exist' END AS ValExist, COUNT(*) cnt
FROM cteMatch
GROUP BY CASE WHEN dst IS NULL THEN N'NonExist' ELSE N'Exist' END
You seem to want:
select count(*)
from sourcetable s
where exists(
select 1
from desttable d
where d.quotationid = s.quotationid or d.quotationnum = s.quotationnum
)
This counts how many rows in the source table have a quotation id or num that exists in the target table. If you want the count of both existing and non-existing rows, I would recommend:
select sum(flag) as cnt_exists, sum(1 - flag) as cnt_not_exists
from (
select
case when exists (
select 1
from desttable d
where d.quotationid = s.quotationid or d.quotationnum = s.quotationnum
) then 1 else 0 end as flag
from sourcetable s
) t

select subquery using data from the select statement?

I have two tables, headers and lines. I need to grab the batch_submission_date from the header table, but sometimes a query for batch_id will return a null for batch_submission_date, but will also return a parent_batch_id, and if we query THAT parent_batch_id as a batch_id, it will then return the correct batch_submission_date.
e.g.
SELECT t1.batch_id,
t1.parent_batch_id,
t2.batch_submission_date
FROM db.headers t1, db.lines t2
WHERE t1.batch_id = '12345';
output = 12345, 99999, null
Then we use that parent batch_id as a batch_id :
SELECT t1.batch_id,
t1.parent_batch_id,
t2.batch_submission_date
FROM db.headers t1, db.lines t2
WHERE t1.batch_id = '99999';
and we get output = 99999,99999,'2018-01-01'
So I'm trying to write a query that will do this for me - anytime a batch_id's batch_submission_date is null, we find that batch_id's parent batch_id and query that instead.
This was my idea - but I just get back null both for bp_batch_submission_date and for new_submission_date.
SELECT
t1.parent_id as parent_id,
t1.BATCH_ID as bp_batch_id,
t2.BATCH_LINE_NUMBER as bp_batch_li,
t1.BATCH_SUBMISSION_DATE as bp_batch_submission_date,
CASE
WHEN t1.BATCH_SUBMISSION_DATE is null
THEN
(SELECT a.BATCH_SUBMISSION_DATE
FROM
db.headers a,
db.lines b
WHERE
a.SD_BATCH_HEADERS_SKEY = b.SD_BATCH_HEADERS_SKEY
and a.parent_batch_id = bp_batch_id
and b.batch_line_number = bp_batch_li
) END as new_submission_date
FROM
db.headers t1,
db.lines t2
WHERE
t1.SD_BATCH_HEADERS_SKEY = t2.SD_BATCH_HEADERS_SKEY
and (t1.BATCH_ID = '12345' or t1.PARENT_BATCH_ID = '12345')
and t2.BATCH_LINE_NUMBER = '1'
GROUP BY
t2.BATCH_CLAIM_LINE_STATUS_DESC,
t1.PARENT_BATCH_ID,
t1.BATCH_ID,
t2.BATCH_LINE_NUMBER,
t1.BATCH_SUBMISSION_DATE;
is what I'm trying to do possible? using the bp_batch_id and bp_batch_li variables
Use CTE (common table expression) to avoid redundant code, then use coalesce() to find parent date in case of null. In your first queries you didn't attach joining condition between two tables, I assumed it's based on sd_batch_headers_skey like in last query.
dbfiddle demo
with t as (
select h.batch_id, h.parent_batch_id, l.batch_submission_date bs_date
from headers h
join lines l on l.sd_batch_headers_skey = h.sd_batch_headers_skey
and l.batch_line_number = '1' )
select batch_id, parent_batch_id,
coalesce(bs_date, (select bs_date from t x where x.batch_id = t.parent_batch_id)) bs_date
from t
where batch_id = 12345;
You could use simpler syntax with connect by and level <= 2 but if in your data there are really rows containing same ids (99999, 99999) then we get cycle error.

SQL select statement in where clause

Hi there I am trying to execute a query but cannot seem to get it right.
SELECT *
FROM table
WHERE id IN (SELECT *
FROM table
WHERE description = 'A')
AND description = 'B'
Above is the query that I have got, the select * from table where description = A works as expected when ran alone I just need to make the where clause to work so I can see any id that has a description of A and B.
You will be getting multiple columns from the sub query when I assume you only want the id column:
SELECT *
FROM table
WHERE id IN (SELECT id
FROM table
WHERE description = 'A')
AND description = 'B'
No need for the select in the where clause
SELECT *
FROM table
WHERE id IN ('A', 'B')
Try this:
SELECT *
FROM table
WHERE description IN ('A', 'B')
it should be:
select * from table where id in (select id from table where description = 'A') and description = 'B'
but this query will give you zero result as you select records with description = 'A' and description = 'B', if you want to get records with either description of A or B, then you should write as
select * from table where description = 'A' or description = 'B'
or
select * from table where description in ('A','B')
SELECT distinct AnaTablo.Id , AnaTablo.FirmaAdi , AnaTablo.FirmaId , AnaTablo.KayitTarihi ,
users.Email Personel, (SELECT top 1 sabitler.Ayar from tblSabitAyarlar sabitler WHERE sabitler.Tur = 29 and sabitler.Deger in
(SELECT top 1 IslemId from tblEFaturaTakipIslem Islem WHERE AnaTablo.Id = Islem.EFaturaTakipId order by KayitTarihi desc))YapilanIslem,
AnaTablo.Eposta , AnaTablo.Aciklama
from tblEFaturaTakip AnaTablo left join AspNetUsers users on AnaTablo.PersonelId = users.Id

Multiple Columns in an "in" statement

I am using DB 2 and i am trying to write a query which checks multiple columns against a given set of values.Like field a, field b and field c against values x,y,z,f. One way that i can think for is writing same condition 3 times with or i.e. field a in ('x','y','z','f') or field b in .... and so on . Please let me know if there is some other efficient and easy way to accomplish this. I am looking for a query like if any of the condition is true return yes else no . Please suggest !
This may or may not work on as400:
create table a (a int not null, b int not null);
insert into a (a,b) values (1,1),(1,3),(2,3),(0,23);
select a.*
from a
where a in (1,2) or b in (1,2);
A B
----------- -----------
1 1
1 3
2 3
Rewriting as a join:
select a.*
from a
join ( values (1),(2) ) b (x)
on b.x in (a.a, a.b);
A B
----------- -----------
1 1
1 3
2 3
Assuming the column data types are the same, Create a subquery joining all the columns you want to search with your IN into one column with a union
SELECT *
FROM (
SELECT
YOUR_TABLE_PRIMARY_KEY
,A AS Col
FROM YOUR_TABLE
UNION ALL
SELECT
YOUR_TABLE_PRIMARY_KEY
,B AS Col
FROM YOUR_TABLE
UNION ALL
SELECT
YOUR_TABLE_PRIMARY_KEY
,C AS Col
FROM YOUR_TABLE
) AS SQ
WHERE
SQ.Col IN ('x','y','z','f')
Make sure to include the table key so you know which row the data refers to
You can create a regular expression that describe the set of characters and use it with xquery
Assuming you're on a supported version of the OS (tested on 7.1 TR6), this should work...
with sel (val) as (values ('x'),('y'),('f'))
select * from mytbl
where flda in (select val from sel)
or fldb in (select val from sel)
or fldc in (select val from sel)
Expanding on the above since your OP asked for "condition is true return yes else no"
Assuming you've got the key to a row to check, would 'yes' or the empty set be good enough? somekey is the key for the row you want to check.
with sel (val) as (values ('x'),('y'),('f'))
select 'yes' from mytbl
where thekey = somekey
and ( flda in (select val from sel)
or fldb in (select val from sel)
or fldc in (select val from sel)
)
It's actually rather difficult to return a value when you don't have a matching row. Here's one way. Note I've switch to 1=yes, 0=no..
with sel (val) as (values ('x'),('y'),('f'))
select 1 from mytbl
where thekey = somekey
and ( flda in (select val from sel)
or fldb in (select val from sel)
or fldc in (select val from sel)
)
UNION ALL
select 0
from sysibm.sysdummy1
order by 1 desc
fetch first row only

return a default record from a sql query

I have a sql query that I run against a sql server database eg.
SELECT * FROM MyTable WHERE Id = 2
This may return a number of records or may return none. If it returns none, I would like to alter my sql query to return a default record, is this possible and if so, how? If records are returned, the default record should not be returned. I cannot update the data so will need to alter the sql query for this.
Another way (you would get an empty initial rowset returned);
SELECT * FROM MyTable WHERE Id = 2
IF (##ROWCOUNT = 0)
SELECT ...
SELECT TOP 1 * FROM (
SELECT ID,1 as Flag FROM MyTable WHERE Id = 2
UNION ALL
SELECT 1,2
) qry
ORDER BY qry.Flag ASC
You can have a look to this post. It is similar to what you are asking
Return a value if no rows are found SQL
I hope that it can guide you to the correct path.
if not exists (SELECT top 1 * FROM mytable WHERE id = 2)
select * from mytable where id= 'whatever_the_default_id_is'
else
select * from mytable where id = 2
If you have to return whole rows of data (and not just a single column) and you have to create a single SQL query then do this:
Left join actual table to defaults single-row table
select
coalesce(a.col1, d.col1) as col1,
coalesce(a.col2, d.col2) as col2,
...
from (
-- your defaults record
select
default1 as col1,
default2 as col2,
...) as d
left join actual as a
on ((1 = 1) /* or any actual table "where" conditions */)
The query need to return the same number of fields, so you shouldn't do a SELECT * FROM but a SELECT value FROM if you want to return a default value.
With that in mind
SELECT value FROM MyTable WHERE Id = 2
UNION
SELECT CASE (SELECT count(*) FROM MyTable WHERE Id = 2)
WHEN 0 THEN 'defaultvalue'
END