SQL Query to retrieve rows having conditional values in a column - sql

I don't know if this question has been asked previously also. If so please direct me to the link.
I have a table that has three columns name, type and date. Type can only be 4 values A, B, C and D
I want to fetch all those records which are of type A, B or C but the condition is that it should only fetch if the same name also has a type of D.
e.g. lets consider this table
Name type Date
abc A 5/7
abc B 6/7
abc D 7/7
xyz A 5/7
xyz D 6/7
lmn A 5/7
lmn B 6/7
lmn C 7/7
So the deal here I need the following result set
ABC 5/7
ABC 6/7
XYZ 5/7
Because ABC and XYZ has a type D the other records of ABC and XYZ are shown. Since lmn does not have a type D it's not included in the result set.

To test if a record exist, you can simply use where exists :
select * from mytable t1 where exists (
select * from mytable t2 where t1.Name=t2.Name and t2.type="D"
);
That's probably self explanatory but here's a reference : http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html
If you want to exclude the D records, you do this :
select * from mytable t1 where t1.type<>"D" and exists (
select * from mytable t2 where t1.Name=t2.Name and t2.type="D"
);

Try this:
SELECT Name, Date
FROM MyTable as mt
WHERE type != 'D'
AND EXISTS
(
SELECT * FROM MyTable as mt2
WHERE mt2.type = 'D' and mt2.name = mt.name
)
You are selecting all records where type is not equal to D and that have a record with a matching name where type IS equal to D

create view all_D as select name from your_table where type=D
select * from your_table where type<>D and name in (select * from all_D)
You could even make it such that instead of having that view you jut put that query in the brackets after "not in"

Related

Insert into table gives different results

I inserted all the rows of a view to a delta table, but after running a query for a particular value I get below results.
Can someone explain to me how this is possible?
A is View and B is Delta(databricks) table.
1.
Select count(*) from A
result: 102.321
2.
Select * from A where id = '11'
id
date
unit
11
2022-09-02
4
3.
Insert Into B Select * From A
OR
CREATE OR REPLACE TABLE B AS ( SELECT * FROM A)
Select count(*) from B '
result: 101.372
5.
Select * from B where id = '11'
id
date
unit
11
2022-09-02
2

SQL Server : select column with 3 matching characters

I am selecting the records from 2 tables in which the 1st table column named DESC (first 3 characters) should match with the project column of the 2nd table.
I want to get the last 2 characters from Table 1 column DESC to be added in my output, but the last 2 characters are not present in Table 2 column project.
select SUBSTRING(a.[DESC], 1, 3)
from Table1 a
join Table2 b on SUBSTRING(a.[DESC], 1, 3) = b.project
Input: 1st Table DESC Column: Value: '2AB F YY'
2nd Table Project Column: Value: '2AB'
Expected Output: Return all the records of value 2AB
Column result:
'2AB YY'
Wrong output: all the records of value starting other then 2AB
One option is as follows
with data
as (
select SUBSTRING(a.[DESC],1,3) as first_3_characters,
,REVERSE(SUBSTRING(REVERSE(a.[DESC]),1,2)) as last_2_char_tab1
,REVERSE(SUBSTRING(REVERSE(b.project),1,2)) as last_2_char_tab2 characters_tab2
from Table1 a
join Table2 b
on SUBSTRING(a.[DESC],1,3) = b.project
)
select *,CONCAT(first_3_characters,last_2_characters)
from data
where last_2_char_tab1 <> last_2_char_tab2
Since you don't seem to need data from Table2, an EXISTS could be used for this.
And RIGHT can be used to get the last N characters of a string.
SELECT
CONCAT(LEFT([DESC], 3),' ', RIGHT([DESC], 2))
FROM Table1 t1
WHERE EXISTS
(
SELECT 1
FROM Table2 t2
WHERE t2.project = LEFT(t1.[DESC], 3)
)
ORDER BY 1;

Where clause between union all in sql?

I have a query that vertically expands data by using Union condition. Below are the 2 sample tables:
create table #temp1(_row_ord int,CID int,_data varchar(10))
insert #temp1
values
(1,1001,'text1'),
(2,1001,'text2'),
(4,1002,'text1'),
(5,1002,'text2')
create table #temp2(_row_ord int,CID int,_data varchar(10))
insert #temp2
values
(1,1001,'sample1'),
(2,1001,'sample2'),
(4,1002,'sample1'),
(5,1002,'sample2')
--My query
select * from #temp1
union
select * from #temp2 where CID in (select CID from #temp1)
order by _row_ord,CID
drop table #temp1,#temp2
So my current output is:
I want to group the details of every client together for which I am unable to use 'where' clause across Union condition.
My desired output:
Any help?! Order by is also not helping me.
I can imagine you want all of the rows for a CID sorted by _row_ord from the first table before the ones from the second table. And the CID should be the outermost sort criteria.
If that's right, you can select literals from your tables. Let the literal for the first table be less than that of the second table. Then first sort by CID, then that literal and finally by _row_ord.
SELECT cid,
_data
FROM (SELECT 1 s,
_row_ord,
cid,
_data
FROM #temp1
UNION ALL
SELECT 2 s,
_row_ord,
cid,
_data
FROM #temp2) x
ORDER BY cid,
s,
_row_ord;
db<>fiddle
If I correctly understand your need, you need the output to be sorted the way that #temp1 rows appear before #temp2 rows for each cid value.
What you could do is generate additional column ordnum assigning values for each table, just for sorting purposes, and then get rid of it in the outer select statement.
select cid, _data
from (
select 1 as ordnum, *
from #temp1
union all
select 2 as ordnum, *
from #temp2 t2
where exists (
select 1
from #temp1 t1
where t1.cid = t2.cid
)
) q
order by cid, ordnum
I have also rewritten your where condition for an equivalent which should work faster using exists operator.
Live DEMO - click me!
Output
cid _data
1001 text1
1001 text2
1001 sample1
1001 sample2
1002 text1
1002 text2
1002 sample1
1002 sample2
Use With. here is my first try with your sql
create table #temp1(_row_ord int,CID int,_data varchar(10))
insert #temp1
values
(1,1001,'text1'),
(2,1001,'text2'),
(4,1002,'text1'),
(5,1002,'text2')
create table #temp2(_row_ord int,CID int,_data varchar(10))
insert #temp2
values
(1,1001,'sample1'),
(2,1001,'sample2'),
(4,1002,'sample1'),
(5,1002,'sample2');
WITH result( _row_ord, CID,_data) AS
(
--My query
select * from #temp1
union
select * from #temp2 where CID in (select CID from #temp1)
)
select * from tmp order by CID ,_data
drop table #temp1,#temp2
result
_row_ord CID _data
1 1001 sample1
2 1001 sample2
1 1001 text1
2 1001 text2
4 1002 sample1
5 1002 sample2
4 1002 text1
5 1002 text2
Union is placed between two result set blocks and forms a single result set block. If you want a where clause on a particular block you can put it:
select a from a where a = 1
union
select z from z
select a from a
union
select z from z where z = 1
select a from a where a = 1
union
select z from z where z = 1
The first query in a union defines column names in the output. You can wrap an output in brackets, alias it and do a where on the whole lot:
select * from
(
select a as newname from a where a = 1
union
select z from z where z = 2
) o
where o.newname = 3
It is important to note that a.a and z.z will combine into a new column, o.newname. As a result, saying where o.newname will filter on all rows from both a and z (the rows from z are also stacked into the newname column). The outer query knows only about o.newname, it knows nothing of a or z
Side note, the query above produces nothing because we know that only rows where a.a is 1 and z.z is 2 are output by the union as o.newname. This o.newname is then filtered to only output rows that are 3, but no rows are 3
select * from
(
select a as newname from a
union
select z from z
) o
where o.newname = 3
This query will pick up any rows in a or z where a.a is 3 or z.z is 3, thanks to the filtering of the resulting union

SQL - Select from column A based on values in column B

Lets say I have a table with 2 columns (a, b) with following values:
a b
--- ---
1 5
1 NULL
2 NULL
2 NULL
3 NULL
My desired output:
a
---
2
3
I want to select only those distinct values from column a for which every single occurrence of this value has NULL in column b. Therefore from my desired output, "1" won't come in because there is a "5" in column b even though there is a NULL for the 2nd occurrence of "1".
How can I do this using a TSQL query?
If I understand correctly, you can do this with group by and having:
select a
from t
group by a
having count(b) = 0;
When you use count() with a column name, it counts the number of non-NULL values. Hence, if all values are NULL, then the value will be zero.
It's fairly simple to do:
SELECT A
FROM table1
GROUP BY A
HAVING COUNT(B) = 0
Grouping by A results in all the rows where the value of A is identical to be transferred into a single row in the output. Adding the HAVING clause enables to filter those grouped rows with an aggregate function. COUNT doesn't count NULL values, so when it's 0, there are no other values in B.
Two more ways to do this:
SELECT a
FROM t
EXCEPT
SELECT a
FROM t
WHERE b IS NOT NULL ;
This would use an index on (a, b):
SELECT a
FROM t
GROUP BY a
WHERE MIN(b) IS NOT NULL ;
Try it like this:
DECLARE #tbl TABLE(a INT, b INT);
INSERT INTO #tbl VALUES(1,5),(1,NULL),(2,NULL),(2,NULL),(3,NULL);
--Your test data
SELECT * FROM #tbl;
--And this is what you want - hopefully...
SELECT DISTINCT tbl.a
FROM #tbl AS tbl
WHERE NOT EXISTS(SELECT * FROM #tbl AS x WHERE x.a=tbl.a AND b IS NOT NULL)
To turn your question on it's head, you want the values from column a where there are no non-null values for that value in column b.
select distinct a
from table1 as t1
where 0 = (select count(*)
from table1 as t2
where t1.a = t2.a
and b is not null)
Sample fiddle is here: http://sqlfiddle.com/#!6/5d1b8/1
This should do it:
SELECT DISTINCT a
FROM t
WHERE b IS NULL
AND a NOT IN (SELECT a FROM t WHERE b IS NOT NULL);

How to update a table column with data from a sub query that fetches duplicate records

I have a table abc which has certain user data (name, ID, date of joining) another table xyz has similar columns but has duplicate data. I want to update date column of table abc with the date value of xyz. But xyz has duplicate data and giving error 'single row subquery returns...'. How do I update data from one table to another when another table has duplicate data. I want to retain the data in table xyz as is and cannot delete duplicate records. The query that I am using is:-
update abc
set date = (select date from
( select a.date from xyz a, abc b where a.emp_id=b.emp_id ))-- this query gives duplicate records hence the error single row subquery...
where exists
( select 1 from ( select a.emp_id from abc a, xyz b where a.emp_id=b.emp_id)
)
If your subquery returns same date for all the records it can be modified as below
select a.date from xyz a, abc b where a.emp_id=b.emp_id and rownum = 1
Try using max or min to get one of the duplicated values.
update abc b
set date = (select max(date) from
xyz a where a.emp_id=b.emp_id )