How to select ID in only 1 criteria - sql

In the dataset shown, I am looking to isolate or show the ID that is only in workbaskets a,b or c but not in d,e or f. I would expect the ID of 111222 to fit that criteria. I have tried this SQL with no luck. Any suggestions?
select id
from table
where workbasket in ('a','b','c') and workbasket not in ('d','e','f')
Workbasket ID
a 111222
a 123456
b 987654
c 112333
d 123456
e 987654
f 112333

select id
from table
where workbasket in ('a','b','c')
EXCEPT
select id
from table
where workbasket in ('d','e','f')

You can also use NOT EXISTS subquery
select id
from table t1
where workbasket in ('a','b','c')
and NOT EXISTS
(
select *
from table t2
where t1.id = t2.id
AND t2.workbasket in ('d','e','f')
)

SQL is by default case-insensitive, but it's possible your database has that flag changed; you also don't need to specify a NOT IN clause here because anything outside of ('a', 'b', 'c') is already ignored by your first clause. TABLE is a SQL term, and may also be causing some kind of problem with your query; alias it if you can - if you can't, wrap it in backticks.
Try this:
SELECT ID
FROM `table`
WHERE Workbasket IN ('a', 'b', 'c');

WITH CTE(Workbasket, ID) AS
(
SELECT 'A',123456 UNION ALL
SELECT 'A',111222 UNION ALL
SELECT 'B',987654 UNION ALL
SELECT 'C',112333 UNION ALL
SELECT 'D',123456 UNION ALL
SELECT 'E',987654 UNION ALL
SELECT 'F',112333
)
SELECT C.ID
FROM CTE AS C
GROUP BY C.ID
HAVING MAX(C.Workbasket) IN('A','B','C')

Related

How to get also the not existing values

I've got a query like this
select column, count(*)
from mytable
where column in ('XXX','YYY','ZZZ',....)
group by column;
But I want also to get a row for values the aren't in the table.
Let's suppose that 'ZZZ' doesn't exist in mytable, I'd like to get:
COLUMN COUNT(*)
XXX 3
YYY 2
ZZZ 0 (or NULL)
Oracle version 10g
Thanks in advance
Mark
In general, you would need to have a second table which contains all the possible column values whose counts you want to appear in the output. For demo purposes only, we can use a CTE for that:
WITH vals AS (
SELECT 'XXX' AS val UNION ALL
SELECT 'YYY' UNION ALL
SELECT 'ZZZ'
)
SELECT t1.val, COUNT(t2.col) AS cnt
FROM vals t1
LEFT JOIN mytable t2
ON t2.col = t1.val
GROUP BY
t1.val;

How to exclude data in second part of a UNION with data from the first part?

I want to make a UNION query. The first SELECT of it is pretty straight, but on the second one I'd like to select all entries in a table, where the IDs are not present in a row of the first part.
Something like this:
SELECT * FROM a
UNION ALL
SELECT * FROM b
WHERE b.id NOT IN (LISTAGG(a.selected_id))
Of yourse, I can't use an aggregat function here. But I don't have an idea how to solve this. Is it even possible?
I'm sure I could do another subselect for the NOT IN clause, but I want to avoid this, as I think this will hit too much to performance.
I think you want something like this:
SELECT a.*
FROM a
UNION ALL
SELECT b.*
FROM b
WHERE NOT EXISTS (SELECT 1 FROM a WHERE b.id = a.selected_id);
If performance is an issue, you want an index on a(selected_id).
This assumes that the columns are the same in the two tables.
In general, you want to use NOT EXISTS with a subquery because it does what you expect when the subquery returns NULL values.
Why not
SELECT * FROM a
UNION ALL
SELECT *
FROM b
WHERE b.id NOT IN (SELECT a.id FROM a)
As Matthew suggested, the NOT IN option is safe to use if a.id is not nullable. Otherwise, a NOT EXISTS would be a better option:
WHERE NOT EXISTS (SELECT 1 FROM a WHERE b.id = a.id);
On the other hand, if it were just about IDs (without mentioning other columns from both tables), is it not just union instead of union all?
select id from a
union
select id from b
because your query says:
give me IDs from b, but not the ones that exist in a
union that with IDs from a
which is (b minus a) union all a
which is a union b
I might be wrong, though; try both options and compare results. Yet again, as Matthew has noted, that approach doesn't make much sense if other columns from both tables are involved.
but i still like to avoid going over the table twice. well, at least
if it is avoidable.
In your posted query,
SELECT * FROM a
UNION ALL
SELECT * FROM b
WHERE b.id NOT IN (LISTAGG(a.selected_id))
I am going to assume that selected_Id is not actually a column in your tables, but rather was your way of saying "the list of ids selected from table a, above".
I am also going to assume that a.id and b.id are both non-nullable, unique keys.
If all those assumptions hold true, you might try this approach:
SELECT nvl(a.id, b.id) id,
nvl(a.col1, b.col1) col1,
nvl(a.col2, b.col2) col2,
-- you get the idea...
FROM a
FULL OUTER JOIN b b ON b.id = a.id;
This approach is more typing, but should access each table only once.
Here is a full example:
create table matta ( id number, col1 varchar2(5), col2 varchar2(5) );
create table mattb ( id number, col1 varchar2(5), col2 varchar2(5) );
insert into matta ( id, col1, col2 ) VALUES ( 1, 'A1.1', 'A1.2');
insert into matta ( id, col1, col2 ) VALUES ( 2, 'A2.1', 'A2.2');
insert into matta ( id, col1, col2 ) VALUES ( 3, 'A3.1', 'A3.2');
insert into matta ( id, col1, col2 ) VALUES ( 4, 'A4.1', 'A4.2');
insert into mattb ( id, col1, col2 ) VALUES ( 3, 'B3.1', 'B3.2');
insert into mattb ( id, col1, col2 ) VALUES ( 4, 'B4.1', 'B4.2');
insert into mattb ( id, col1, col2 ) VALUES ( 5, 'B5.1', 'B5.2');
COMMIT;
SELECT nvl(a.id, b.id),
nvl(a.col1, b.col1),
nvl(a.col2, b.col2)
FROM matta a
FULL OUTER JOIN mattb b ON b.id = a.id
ORDER BY 1;
+----+------+------+
| ID | COL1 | COL2 |
+----+------+------+
| 1 | A1.1 | A1.2 |
| 2 | A2.1 | A2.2 |
| 3 | A3.1 | A3.2 |
| 4 | A4.1 | A4.2 |
| 5 | B5.1 | B5.2 |
+----+------+------+
One more option to try is the LEFT JOIN of b to a end exclude the matching rows, where b.id = a.selected_id:
SELECT a.* FROM a
UNION ALL
SELECT b.* FROM b
LEFT JOIN a ON b.id = a.selected_id
WHERE a.selected_id IS NULL;

basic sql - how to pivot using oracle sql

Very basic question
Right now my query is like
select table.a, table.b, table.c from table
A B C
1 2 3
.
I need my output to be
NAME ID
A 1
B 2
C 3
.
Is there a way that I can pivot my current output or query this table in a different way?
Thanks!
You need UNPIVOT:
select * from table1 unpivot (id for name in (a,b,c));
Select 'A' as name, (
select A
from table1
) as ID
union all
Select 'B', (
select B
from table1
) as ID
union all
Select 'C', (
select C
from table1
) as ID

SQL - Getting Most Recent Date From Multiple Columns

Assume a rowset containing the following
EntryID Name DateModified DateDeleted
-----------------------------------------------
1 Name1 1/2/2003 NULL
2 Name1 1/3/2005 1/5/2008
3 Name1 1/3/2006 NULL
4 Name1 NULL NULL
5 Name1 3/5/2008 NULL
Clarification:
I need a single value - the largest non-null date from BOTH columns. So the largest of all ten cells in this case.
SELECT MAX(CASE WHEN (DateDeleted IS NULL OR DateModified > DateDeleted)
THEN DateModified ELSE DateDeleted END) AS MaxDate
FROM Table
For MySQL, Postgres or Oracle, use the GREATEST function:
SELECT GREATEST(ISNULL(t.datemodified, '1900-01-01 00:00:00'),
ISNULL(t.datedeleted, '1900-01-01 00:00:00'))
FROM TABLE t
Both Oracle and MySQL will return NULL if a NULL is provided. The example uses MySQL null handling - update accordingly for the appropriate database.
A database agnostic alternative is:
SELECT z.entryid,
MAX(z.dt)
FROM (SELECT x.entryid,
x.datemodified AS dt
FROM TABLE x
UNION ALL
SELECT y.entryid
y.datedeleted AS dt
FROM TABLE y) z
GROUP BY z.entryid
As a general solution, you could try something like this:
select max(date_col)
from(
select max(date_col1) AS date_col from some_table
union
select max(date_col2) AS date_col from some_table
union
select max(date_col3) AS date_col from some_table
...
)
There might be easier ways, depending on what database you're using.
How about;
SELECT MAX(MX) FROM (
SELECT MAX(DateModified) AS MX FROM Tbl
UNION
SELECT MAX(DateDeleted) FROM Tbl
) T
The answer depends on what you really want. If you simply want the most recent of the two date values then you can do:
Select Max(DateModified), Max(DateDeleted)
From Table
If you are asking for the largest value from either column, then you can simply do:
Select Case
When Max(DateModified) > Max(DateDeleted) Then Max(DateModified)
Else Max(DateDeleted)
End As MaxOfEitherValue
From Table
The above are all valid answers;
But I'm Not sure if this would work?
select IsNull((
select MAX(DateModified)
from table
)
,
(
select MAX(DateDeleted)
from table
)
) as MaxOfEitherValue
from table
Edit 1:
Whilst in the shower this morning, I had another solution:
Solution 2:
select MAX(v) from (
select MAX(DateModified) as v from table
union all
select MAX(DateDeleted) as v from table
) as SubTable
Edit 3:
Damn it, just spotted this is the same solution as Alex k. sigh...
How to find the Latest Date from the columns from Multiple tables
e.g. if the Firstname is in Table1, Address is in Table2, Phone is in Table3:
When you are using with main SELECT statement while selecting other columns it is best written as :
SELECT Firstname
,Lastname
,Address
,PhoneNumber
,
,(SELECT max(T.date_col) from(select max(date_col1) AS date_col from Table1 Where ..
union
select max(date_col2) AS date_col from Table2 Where..
union
select max(date_col3) AS date_col from Table3 Where..
) AS T
) AS Last_Updated_Date
FROM Table T1
LEFT JOIN Table T2 ON T1.Common_Column=T2.Common_Column
LEFTJOIN Table T3 ON T1.Common_Column=T3.Common_Column

Interesting SQL issue

I have a SQL problem I am trying to digest. I am using SQL Server 2005.
In a table I have data as such:
ID Type
1 A
2 A
3 A
3 B
4 B
I need to find all of the IDs that have a Type of both A and B.
Use the INTERSECT operator:
SELECT DISTINCT ID FROM [Table] WHERE Type = 'A'
INTERSECT
SELECT DISTINCT ID FROM [Table] WHERE Type = 'B'
select distinct a.id
from table a
join table b on a.id=b.id
where a.type='A'
and b.type='B';
With a semi-join (no sorting, only index seek on B):
select a.id from table a
where a.type = 'A'
and exists (select * from table b where a.id = b.id and b.type = 'B')
If you want to abstract the problem a little bit and find cases where rows with the same id contain different values in the type column, you can check for <> like this:
DECLARE #TestTable TABLE (thisid int, thisval varchar(1))
INSERT INTO #TestTable VALUES (1, 'A')
INSERT INTO #TestTable VALUES (2, 'A')
INSERT INTO #TestTable VALUES (3, 'A')
INSERT INTO #TestTable VALUES (3, 'B')
INSERT INTO #TestTable VALUES (4, 'B')
SELECT DISTINCT thisid
FROM #TestTable a
WHERE EXISTS
( SELECT *
FROM #TestTable b
WHERE a.thisid=b.thisid AND a.thisval<>b.thisval)
-- www.caliberwebgroup.com
This returns:
3
select id, count(type = 'A') as a_count, count(type = 'B') as b_count
from your_table
group by 1
having a_count > 0 and b_count > 0;
At least, this works in sane SQL environments. Dunno if it works in yours.
I was not looking at other answers, but still posting. lol
SELECT distinct t1.ID
FROM table1 AS t1
WHERE exists
(select t2.ID from table1 t2 where t2.type="A" and t2.ID=t1.ID)
and exists
(select t3.ID from table1 t3 where t3.type="B" and t3.ID=t1.ID);
SELECT Id FROM tableX AS x, tableX AS y
WHERE x.id = y.id AND x.type = 'A' AND y.type = 'B'
This is very simple
Declare #t table([ID] INT, [Type] VARCHAR(2))
INSERT INTO #t SELECT 1, 'A' UNION ALL SELECT 2,'A' UNION ALL SELECT 3,'A'
UNION ALL SELECT 3,'B' UNION ALL SELECT 4,'B' UNION ALL SELECT 5,'A' UNION ALL SELECT 5,'A'
;WITH CTE AS
(
SELECT Rn = Row_NUMBER() OVER(PARTITION BY [ID],[TYPE] ORDER BY [ID])
,*
FROM #t
)
SELECT ID
FROM CTE
WHERE Rn =1 AND ([Type]='A' or [Type]='B')
GROUP BY [ID]
HAVING (COUNT([ID])>1)
Output:
id
3
this would help if there are "unknown" amounts of types and you want to find all IDs which have all of types
select id from yourtable group by id having count(*)=(select count(distinct type) from yourtable)
select id
from idtypedata
group by id
having
sum(
case type
when 'A' then 1
when 'B' then 2
-- when 'C' then 4
-- when 'D' then 8
end
) & 1 = 1
And
sum(
case type
when 'A' then 1
when 'B' then 2
-- when 'C' then 4
-- when 'D' then 8
end
) & 2 = 2