How to check existence of data in a table from a where clause in sql server 2008? - sql

Suppose I have a table with columns user_id, name and the table contains data like this:
user_id name
------- -----
sou souhardya
cha chanchal
swa swapan
ari arindam
ran ranadeep
If I want to know these users (sou, cha, ana, agn, swa) exists in this table or not then I want output like this:
user_id it exists or not
------- -----------------
sou y
cha y
ana n
agn n
swa y
As ana and aga do not exist in the table it must show "n" (like the above output).

Assuming your existing checklist is not on the database, you will have to assemble a query containing those. There are many ways of doing it. Using CTEs, it would look like this:
with cte as
(
select 'sou' user_id
union all
select 'cha'
union all
select 'ana'
union all
select 'agn'
union all
select 'swa'
)
select
cte.user_id,
case when yt.user_id is null then 'n' else 'y' end
from cte
left join YourTable yt on cte.user_id = yt.user_id
This also assumes user_id is unique.
Here is the SQLFiddle with the proof of concept: http://sqlfiddle.com/#!3/e023a0/4

Assuming you're just testing this manually:
DECLARE #Users TABLE
(
[user_id] VARCHAR(50)
)
INSERT INTO #Users
SELECT 'sou'
UNION SELECT 'cha'
UNION SELECT 'ana'
UNION SELECT 'agn'
UNION SELECT 'swa'
SELECT a.[user_id]
, [name]
, CASE
WHEN b.[user_id] IS NULL THEN 'N'
ELSE 'Y'
END AS [exists_or_not]
FROM [your_table] a
LEFT JOIN #Users b
ON a.[user_id] = b.[user_id]

You didn't provide quite enough information to provide a working example, but this should get you close:
select tbl1.user_id, case tbl2.user_id is null then 'n' else 'y' end
from tbl1 left outer join tbl2 on tbl1.user_id = tbl2.user_id

;with usersToCheck as
(
select 'sou' as userid
union select 'cha'
union select 'ana'
union select 'agn'
union select 'swa'
)
select utc.userid,
(case when exists ( select * from usersTable as ut where ut.user_id = utc.userid) then 'y' else 'n' end)
from usersToCheck as utc

Related

How to write redshift aws query to search for a value in comma delimited values

table1
user_id
country_code
1
'IN,AU,AC'
2
'MX,IN'
table2
user_id
valid_country
1
'IN'
1
'AU'
2
'MX'
3
'YT'
4
'RU'
As you can see, some entries in the country_code column are multiple codes separated by commas. I would like to print user_id in table1 and their corresponding country_code only if they are valid. To check for validity here I need to use table2 which has user_id and valid_country.
The desired output is:
user_id
country_code
1
'IN'
1
'AU'
2
'MX'
Query looks like
select tb1.user_id, country_code from table1 tb1, table2 tb2 where
tb1.user_id=tb2.user_id and <Here I need to check if tb2.country_code
is there in tb1.country_code (codes separated by commas)>
Are there any simple solution that I could check valid_country in the comma separated values.
The simple way isn't always the best. There are a number of corner cases that can arise here (like are all country codes 2 letters). That said a LIKE clause would be simple:
select tb1.user_id, valid_country as country_code
from table1 tb1, table2 tb2
where tb1.user_id=tb2.user_id
and tb1.country_code like '%'||tb2.valid_country||'%'
Or if we are to put this in modern SQL syntax:
select tb1.user_id, valid_country as country_code
from table1 tb1 join table2 tb2
on tb1.user_id=tb2.user_id
and tb1.country_code like '%'||tb2.valid_country||'%'
Try this:
a) Verticalise tb1 by CROSS JOINing it with a series of consecutive integers (which I supply in a Common Table Expression), and applying the SPLIT_PART() function to break the comma delimited list into single element.
b) INNER JOIN the verticalised result with the valid user_id/country code combinations table on an equi-join on both columns.
WITH
-- your table 1, don't use in end query ...
tb1(user_id,country_code) AS (
SELECT 1,'IN,AU,AC'
UNION ALL SELECT 2,'MX,IN'
)
,
-- your table 2, don't use in end query ...
tb2(user_id,valid_country) AS (
SELECT 1,'IN'
UNION ALL SELECT 1,'AU'
UNION ALL SELECT 2,'MX'
UNION ALL SELECT 3,'YT'
UNION ALL SELECT 4,'RU'
)
-- real query starts here, replace following comma with "WITH" ...
,
i(i) AS ( -- need a series of integers ...
SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
)
,
vertical AS (
SELECT
tb1.user_id
, i
, SPLIT_PART(country_code,',',i) AS valid_country
FROM tb1 CROSS JOIN i
WHERE SPLIT_PART(country_code,',',i) <> ''
)
SELECT
vertical.user_id
, vertical.valid_country
FROM vertical
JOIN tb2 USING(user_id,valid_country)
ORDER BY vertical.user_id,vertical.i
;
-- out user_id | valid_country
-- out ---------+---------------
-- out 1 | IN
-- out 1 | AU
-- out 2 | MX

Consolidate information (time serie) from two tables

MS SQL Server
I have two tables with different accounts from the same customer:
Table1:
ID
ACCOUNT
FROM
TO
1
A
01.10.2019
01.12.2019
1
A
01.02.2020
09.09.9999
and table2:
ID
ACCOUNT
FROM
TO
1
B
01.12.2019
01.01.2020
As result I want a table that summarize the story of this costumer and shows when he had an active account and when he doesn't.
Result:
ID
FROM
TO
ACTIV Y/N
1
01.10.2019
01.01.2020
Y
1
02.01.2020
31.01.2020
N
1
01.02.2020
09.09.9999
Y
Can someone help me with some ideas how to proceed?
This is the typical gaps and island problem, and it's not usually easy to solve.
You can achieve your goal using this query, I will explain it a little bit.
You can test on this db<>fiddle.
First of all... I have unified your two tables into one to simplify the query.
-- ##table1
select 1 as ID, 'A' as ACCOUNT, convert(date,'2019-10-01') as F, convert(date,'2019-12-01') as T into ##table1
union all
select 1 as ID, 'A' as ACCOUNT, convert(date,'2020-02-01') as F, convert(date,'9999-09-09') as T
-- ##table2
select 1 as ID, 'B' as ACCOUNT, convert(date,'2019-12-01') as F, convert(date,'2020-01-01') as T into ##table2
-- ##table3
select * into ##table3 from ##table1 union all select * from ##table2
You can then get your gaps and island using, for example, a query like this.
It combines recursive cte to generate a calendar (cte_cal) and lag and lead operations to get the previous/next record information to build the gaps.
with
cte_cal as (
select min(F) as D from ##table3
union all
select dateadd(day,1,D) from cte_cal where d < = '2021-01-01'
),
table4 as (
select t1.ID, t1.ACCOUNT, t1.F, isnull(t2.T, t1.T) as T, lag(t2.F, 1,null) over (order by t1.F) as SUP
from ##table3 t1
left join ##table3 t2
on t1.T=t2.F
)
select
ID,
case when T = D then F else D end as "FROM",
isnull(dateadd(day,-1,lead(D,1,null) over (order by D)),'9999-09-09') as "TO",
case when case when T = D then F else D end = F then 'Y' else 'N' end as "ACTIV Y/N"
from (
select *
from cte_cal c
cross apply (
select t.*
from table4 t
where t.SUP is null
and (
c.D = t or
c.D = dateadd(day,1,t.T)
)
) t
union all
select F, * from table4 where T = '9999-09-09'
) p
order by 1
option (maxrecursion 0)
Dates like '9999-09-09' must be treated like exceptions, otherwise I would have to create a calendar until that date, so the query would take long time to resolve.

SQL: return true/false if a related record is presented

I have two tables:
ASSIGNMENTS (ID)
ASSIGNMENT_REVIEWS (ID, ASSIGNMENT_ID)
As a result of selecting I'd like to retrieve a flag if a review is already presented for the assignment. How to do it in the best way?
You are looking for the exists statement:
select
id,
case when exists (
select 1 from assignment_reviews where assignment_reviews.assignment_id = assignments.id
) then 1 else 0 end as hasReview
from
assignments
You can use a left join with nvl2() function(returns the
value in the 2nd argument if the 1st argument is not null, otherwise
returns the 3rd argument practically )
with assignments(id) as
(
select 101 from dual union all
select 102 from dual
), assignments_reviews(id,assignment_id) as
(
select 855, 101 from dual
)
select a.id,
nvl2(r.assignment_id,1,0) as already_presented
from assignments a
left join assignments_reviews r
on r.assignment_id = a.id;
ID ALREADY_PRESENTED
101 1
102 0
Demo

How to merge two columns from CASE STATEMENT of DIFFERENT CONDITION

My expected result should be like
----invoiceNo----
T17080003,INV14080011
But right now, I've come up with following query.
SELECT AccountDoc.jobCode,AccountDoc.shipmentSyskey,AccountDoc.docType,
CASE AccountDoc.docType
WHEN 'M' THEN
JobInvoice.invoiceNo
WHEN 'I' THEN
(STUFF((SELECT ', ' + RTRIM(CAST(AccountDoc.docNo AS VARCHAR(20)))
FROM AccountDoc LEFT OUTER JOIN JobInvoice
ON AccountDoc.principalCode = JobInvoice.principalCode AND
AccountDoc.jobCode = JobInvoice.jobCode
WHERE (AccountDoc.isCancelledByCN = 0)
AND (AccountDoc.docType = 'I')
AND (AccountDoc.jobCode = #jobCode)
AND (AccountDoc.shipmentSyskey = #shipmentSyskey)
AND (AccountDoc.principalCode = #principalCode) FOR XML
PATH(''), TYPE).value('.','NVARCHAR(MAX)'),1,2,' '))
END AS invoiceNo
FROM AccountDoc LEFT OUTER JOIN JobInvoice
ON JobInvoice.principalCode = AccountDoc.principalCode AND
JobInvoice.jobCode = AccountDoc.jobCode
WHERE (AccountDoc.jobCode = #jobCode)
AND (AccountDoc.isCancelledByCN = 0)
AND (AccountDoc.shipmentSyskey = #shipmentSyskey)
AND (AccountDoc.principalCode = #principalCode)
OUTPUT:
----invoiceNo----
T17080003
INV14080011
Explanation:
I want to select docNo from table AccountDoc if AccountDoc.docType = I.
Or select invoiceNo from table JobInvoice if AccountDoc.docType = M.
The problem is what if under same jobCode there have 2 docType which are M and I, how I gonna display these 2 invoices?
You can achieve this by using CTE and FOR XML. below is the sample code i created using similar tables you have -
Create table #AccountDoc (
id int ,
docType char(1),
docNo varchar(10)
)
Create table #JobInvoice (
id int ,
invoiceNo varchar(10)
)
insert into #AccountDoc
select 1 , 'M' ,'M1234'
union all select 2 , 'M' ,'M2345'
union all select 3 , 'M' ,'M3456'
union all select 4 , 'I' ,'I1234'
union all select 5 , 'I' ,'I2345'
union all select 6 , 'I' ,'I3456'
insert into #JobInvoice
select 1 , 'INV1234'
union all select 2 , 'INV2345'
union all select 3 , 'INV3456'
select *
from #AccountDoc t1 left join #JobInvoice t2
on t1.id = t2.id
with cte as
(
select isnull( case t1.docType WHEN 'M' THEN t2.invoiceNo WHEN 'I' then
t1.docNo end ,'') invoiceNo
from #AccountDoc t1 left join #JobInvoice t2
on t1.id = t2.id )
select invoiceNo + ',' from cte For XML PATH ('')
You need to pivot your data if you have situations where there are two rows, and you want two columns. Your sql is a bit messy, particularly the bit where you put an entire select statement inside a case when in the select part of another query. These two queries are virtually the same, you should look for a more optimal way of writing them. However, you can wrap your entire sql in the following:
select
Jobcode, shipmentsyskey, [M],[I]
from(
--YOUR ENTIRE SQL GOES HERE BETWEEN THESE BRACKETS. Do not alter anything else, just paste your entire sql here
) yoursql
pivot(
max(invoiceno)
for docType in([M],[I])
)pvt

ORACLE MAX GROUP BY

I am using Oracle (SQL Developer). Please find below the example and an outcome which would like to get (purpose of select is to find out people who submitted project A and have not done any activities in project B yet):
Data table:
CREATE TABLE "XXX"."TABLE1"
( "STATUS" VARCHAR2(20 BYTE),
"PROJECT_NAME" VARCHAR2(20 BYTE),
"VERSION_NUMBER" NUMBER,
"PERSON" VARCHAR2(20 BYTE)
);
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','1','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('NEW','A','2','JOHN');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','A','0','MARY');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','B','0','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('NEW','B','1','PETER');
Insert into XXX.TABLE1 (STATUS,PROJECT_NAME,VERSION_NUMBER,PERSON) values ('SUBMITTED','B','0','JOHN');
Created table should look like this:
TABLE1:
TABLE1.STATUS TABLE1.PROJECT_NAME TABLE1.VERSION_NUMBER TABLE1.PERSON
SUBMITTED A 0 PETER
SUBMITTED A 0 JOHN
SUBMITTED A 1 JOHN
NEW A 2 JOHN
SUBMITTED A 0 MARY
SUBMITTED B 0 PETER
NEW B 1 PETER
SUBMITTED B 0 JOHN
Result what I want get is this:
STATUS PROJECT_NAME VERSION_NUMBER PERSON STATUS_1 PROJECT_NAME_1 VERSION_NUMBER_1 PERSON_1
SUBMITTED A 0 PETER NEW B 1 PETER
SUBMITTED A 1 JOHN SUBMITTED B 0 JOHN
SUBMITTED A 0 MARY
Select which I am using now is:
select t.*,v.*
from TABLE1 t
left outer join ( select u.*
from TABLE1 u
where exists (select max(z.VERSION_NUMBER)
,z.PERSON
,z.PROJECT_NAME
from TABLE1 z
where z.PROJECT_NAME = 'B'
and u.PROJECT_NAME = z.PROJECT_NAME
and u.PERSON = z.PERSON
group by z.PERSON, z.PROJECT_NAME
having u.VERSION_NUMBER = max(z.VERSION_NUMBER))) v
on t.PERSON = v.PERSON
where exists (select max (w.VERSION_NUMBER)
,w.PERSON
,w.PROJECT_NAME
from TABLE1 w
where w.PROJECT_NAME = 'A'
and w.STATUS = 'SUBMITTED'
and t.PROJECT_NAME = w.PROJECT_NAME
and t.PERSON = w.PERSON
group by w.PERSON, w.PROJECT_NAME
having t.VERSION_NUMBER = max (w.VERSION_NUMBER))
QUESTION: What would be best(right) way to write such select (best practice), should I better use Analytic functions or use something else instead of EXISTS?
I think you've over-complicated this...
WITH
project_status (status, project_name, version_number, person)
AS
(SELECT 'SUBMITTED','A','0','PETER' FROM dual UNION ALL
SELECT 'SUBMITTED','A','0','JOHN' FROM dual UNION ALL
SELECT 'SUBMITTED','A','1','JOHN' FROM dual UNION ALL
SELECT 'NEW','A','2','JOHN' FROM dual UNION ALL
SELECT 'SUBMITTED','A','0','MARY' FROM dual UNION ALL
SELECT 'SUBMITTED','B','0','PETER' FROM dual UNION ALL
SELECT 'NEW','B','1','PETER' FROM dual UNION ALL
SELECT 'SUBMITTED','B','0','JOHN' FROM dual
)
SELECT DISTINCT
ps.person
,ps.project_name
,ps.status
FROM
project_status ps
WHERE 1=1
AND ps.project_name = 'A'
AND ps.status = 'SUBMITTED'
AND NOT EXISTS
(SELECT 1
FROM project_status ps2
WHERE ps2.person = ps.person
AND ps2.project_name = 'B'
)
;
purpose of select is to find out people who submitted project A and
have not done any activities in project B yet
If your purpose is just to get the people, then you don't need the complete rows. One method to answer this is to use group by and having:
select t1.person
from "XXX"."TABLE1" t1
group by t1.person
having sum(case when project_name = 'A' and status = 'New' then 1 else 0 end) > 0 and
sum(case when project_name = 'B' then 1 else 0 end) = 0;
If you need the complete rows, then Christian has a reasonable solution.