i am trying to change the IN clause with EXISTS clause but not getting the desired results
OLD SCRIPT
delete from ABC a
where column1 IN (select DISTINCT column1
from BCD b
where b.column2 = a.column2
and b.column3 = 'N')
or a.column3 = "Y";
when i am changing this to
delete from ABC a
where EXISTS (select column1
from BCD b
where b.column2 = a.column2
and b.column3 = 'N')
or a.column3 = "Y";
i am not getting the desired results i have doubt that it is due to "or" condition used in the last.
Need help to resolve this.
The problem is not due to OR condition.
Your OLD script is validating the values against COLUMN1
where column1 IN (select DISTINCT column1 from BCD b where b.column2=a.column2 and b.column3= 'N')
But, the other script checks if any records exist in the subquery.
where EXISTS (select column1 from BCD b where b.column2=a.column2 and b.column3= 'N')
To summarize, query with IN verifies the existence of returned values in column1, while EXISTS just checks if the subquery returns 0 or more rows.
You missed the column1 filter. Remember that the projected column in an exists subquery isn’t doing anything - you’re only checking that the subquery returns rows, not what they are. I typically use select null in (not) exists to make this obvious to the reader
delete from ABC a
where EXISTS
(select null
from BCD b
where b.column2=a.column2
And b.column1 = a.column1
and b.column3= 'N')
or a.column3= "Y";
Related
I have 2 tables. These two tables have one-to-many relations.
TABLE - A
column1 column2
1 label1
2 label2
TABLE - B
Bcolumn1 Bcolumn2 Bcolumn3
1 value1 value4
1 value2 value5
2 value3 value6
RESULT TABLE
column1 column2 json
1 label1 [{"Bcolumn":value1,"Bcolumn":value4},{"Bcolumn":value2,"Bcolumn":value5}]
2 label2 [{"Bcolumn":value3,"Bcolumn":value6}]
I want to get RESULT TABLE1 using TABLE - A and TABLE - B.
how can I get this result?
Thank you.
Use SQLite's JSON1 Extension functions:
SELECT a.column1, a.column2,
json_group_array(json_object('Bcolumn', b.Bcolumn2, 'Bcolumn', b.Bcolumn3)) json
FROM tableA a INNER JOIN tableB b
ON b.Bcolumn1 = a.column1
GROUP BY a.column1;
See the demo.
What you are looking for in sqlite is the group_concat() function. It's tricky, cause you have he values you want to concat in 2 different columns. Basically you can do the following
select
a.column1
, a.column2
, '[{' || group_concat('"Bcolumn":' || b.bcolumn2 || '"Bcolumn":' || b.bcolumn3,'};{') || '}]' as json_output
from tablea a
inner join tableb b on
a.column1 = b.bcolumn1
group by
a.column1
, a.column2
;
I tested this solution with MSSQL 2019 and string_agg(), but from the documentation (https://www.sqlitetutorial.net/sqlite-group_concat/) this should work just as well in sqlite.
The trick is to use '};{' as separator, because like this, you will only have to care about the opening and closing brackets and nothing in the middle.
I have a question about finding identical rows from one table to another. I have a table for users to ask for information. So with that the query will be ran against another table. Both tables are identical except for the ID columns.
The ID columns are not involved in the query except for the
SELECT TOP 1 *
FROM searchTable
ORDER BY searchid DESC
part.
My query looks like this
SELECT TOP 1 *
FROM searchTable
ORDER BY searchid DESC(SELECT A.column1, A.column2,..............
FROM dbo.searchTable A
WHERE EXISTS (SELECT * FROM realTable B
WHERE A.Column1 = B.Column1
AND A.Column2 = B.Column2,
.......
AND A.lastColumn = B.lastColumn))
What I get when running the query is the last entered query from the query table, which is correct, but I get all the rows listed from the realTable as if everything after WHERE EXISTS is pointless. What I need is the single row query from the queryTable to list all the rows that are identical to it from the realTable. Not all the rows the realTable has.
You can use inner join instead of exists.
select B.* from searchTable A
inner join realTable B
on A.Column1 = B.Column1
and A.Column2 = B.Column2
.
.
.
It will return all the records in your realTable which have identical columns with your searchTable.
I was able to get it to work the way I needed by understanding the logic in the last suggestion.
It looks like this.
DECLARE #searchID int = (SELECT MAX(searchID) FROM searchTable)
SELECT Column1, Column2.............LastColumn FROM realTable B
WHERE EXISTS(SELECT * FROM searchTable A WHERE searchID = #searchID AND A.Column1=B.Column1 AND A.Column2=B.Column2................A.LastColumn=B.LastColumn)
Now the last search in the searchTable will give me all the rows in the realTable that match that search.
Backstory,
My company runs redundant call recording servers, each with a list of extensions.
We query these using SQL. I can see there is a 20+ extension difference between the two servers. These are columns that exist in the same table...so essentially I need to do the following:
Compare column1 data from column 2 'server1' in table system.name with column1 data from column 2 'server2' in table system.name and display those that DO NOT exist on both, but exist on one or the other.
Based on what I can undertand from your question
Select column1
from table1 a
where column2 = 'server1'
and not exists
(select *
from table1 b
where a.column1 = b.column1
and b.column2 = 'server2'
)
UNION
Select column1
from table1 a
where column2 = 'server2'
and not exists
(select *
from table1 b
where a.column1 = b.column1
and b.column2 = 'server1'
)
I am a little out of practice with SQL and I am trying to verify some data that has been converted in a system. Some of the queries I originally developed prior to the conversion are not proving out the work. I have been able to trace the source data back and verify that conversion was correct, but this is on an account by account basis. I would like to have a query to show the full dataset.
I have been able to work a solution down to 2 queries, but I cannot figure out how to combine them into one piece to show the full data set, where one value from the first query needs to be an element in the second query.
Query 1
select distinct
CreatedDate, AccountNum
From
Table1 A
Join
Table2 B on A.Column1 = B.Column1 and a.Column2 = b.Column2
Join
Table3 C on A.Column3 = C.Column3 and A.Column4 = C.Column4
where
Condition A and Condition B
Query 2
Select distinct
AccountNum, Responsible
From
Table3 D
Join
Table4 E on D.Column1 = E.Column2
where
StartDate <= 'DateValue' and EndDate > 'DateValue'
I would like to use the CreatedDate value from query 1 as the DateValue in query 2, but I have not found a solution to give the results I am looking for.
If I add a qualifier to each query, like account number, I end up with 1 result from query 1. I then put that CreatedDate into query 2 and I get the results I want. If I only have the account number on the 2nd query, I get two results, one from time period A to B with a responsible value of X and the 2nd from time period C to D with Responsible Value Y, which is where the CreateDate value falls between. Everything I have tried to combine these queries either ends up with a Responsible value of X (or no results), when I want that Y value.
I have not been able to successfully integrate the two queries, so that I can have that CreatedDate value passed as a parameter to figure out the Responsible value.
A solution that would work would be to create an intermediate table for the results of the 1st query and then join that table to 2nd query. However, I do not have access to create/insert/update tables/records on the database, so I cannot use this method.
I think you are looking for this
SELECT DISTINCT accountnum,
responsible
FROM table1 A
JOIN table2 B
ON A.column1 = B.column1
AND a.column2 = b.column2
JOIN table3 C
ON A.column3 = C.column3
AND A.column4 = C.column4
JOIN table4 D
ON D.column1 = C.column2
AND startdate <= createddate
AND enddate > createddate
where Condition A and Condition B
Note: You may have to add proper alias name to the columns
Select distinct AccountNum, Responsible
From Table3 D
Join Table4 E on D.Column1 = E.Column2
Join (
select distinct CreatedDate, AccountNum
From Table1 A
Join Table2 B on A.Column1 = B.Column1 and a.Column2 = b.Column2
Join Table3 C on A.Column3 = C.Column3 and A.Column4 = C.Column4
where Condition A and Condition B
) X
on D.AccountNum=X.AccountNum
and D.StartDate <= X.CreatedDate and EndDate > X.CreatedDate
Another solution is to make the first query into a table-valued UDF:
Create function GetCreateDateAndAcctId([Parameters for 2 conditions here])
Returns table As
Return
select distinct CreatedDate, AccountNum
From Table1 a
Join Table2 b
on b.Column1 = a.Column1
and b.Column2 = a.Column2
Join Table3 c
on c.Column3 = a.Column3
and c.Column4 = a.Column4
where condition1 -- here put predicate
and condition2 -- using input parameters
Then, to use it, just include it as a table in your second query like this:
Select distinct AccountNum, Responsible
From Table3 d
Join Table4 e
on e.Column2 = d.Column1
outer apply dbo.GetCreateDateAndAcctId(Parameters) cd
where StartDate <= cd.CreatedDate and EndDate > cd.CreatedDate
If you do this, the logic for the first query remains in a separate database object for reusability (you can use it in any other process without copying it). and better maintainability, (it's in only one place for fixing bugs and enhancements, etc. Also, since it's a table valued UDF, the SQL Server query processor will actually combine it with the second query's SQL into a single reusable compiled execution plan.
i have two tables say A and B. B is a subset of A. what i want to do is this : Add a flag column to table A(only for viewing, not permanently in the table) and the value of this flag should be yes for common rows between A and B and no for non common rows. For ex:
A table
Column1 Column2 Column3
X1 X2 X3
Y1 Y2 Y3
Z1 Z2 Z3
select * from A where column1=Y1; to get B
now my final output should be
Column1 Column2 Column3 FLAG
X1 X2 X3 NO
Y1 Y2 Y3 YES
Z1 Z2 Z3 NO
i have to everything below the code block in 1 sql statement(extracting B and adding flag).
i am just able to extract B. unable to add flag
Using oracle 11.2.0.2.0,sqlplus
Use an outer join to conditionally link tables A and B, then use a CASE() statement to test whether a given row in A matches a row in B.
select a.*
, case when b.column1 is not null then 'YES' else 'NO' end as flag
from a left outer join b
on a.column1 = b.column1
Note that this only works properly when there is just 0 or 1 instances of B.COLUMN1. If B contains multiple instances of any value of COLUMN1 then you can use this variant:
select a.*
, case when b.column1 is not null then 'YES' else 'NO' end as flag
from a left outer join ( select distinct column1 from b ) b
on a.column1 = b.column1
You could try something like this:
SELECT A.*,
CASE WHEN EXISTS
(SELECT Column1 FROM B WHERE Column1=A.Column1)
THEN "YES"
ELSE "NO"
END
FROM A
My PL-SQL is a bit rusty, example taken from here
You can also do a LEFT JOIN on B, and see if B.Column1 is NULL or not.
SELECT A.*, 'NO'
FROM A
WHERE NOT EXISTS
(SELECT 1 FROM B
WHERE B.COL1 = A.COL1
AND B.COL2 = A.COL2
AND B.COL3 = A.COL3) -- gets records only in A
UNION ALL
(SELECT B.*, 'YES') -- gets B records which are a subset of A
Since B is a subset of A - you already know these records should be tagged with a YES for your aliased column.
The classical way of removing records from one recordset where they exist or don't exist in another recordset is of course using the EXISTS clause.
The advantage of the EXISTS clause is it is a boolean operator and returns TRUE or FALSE to the call. And this return happens without the need for a full scan of the table - it is therefore faster (generally).
You could also choose to use a MINUS clause, it might be more efficient. Try turning on the EXPLAIN PLAN.