Say, I have the following:
WITH T1 as (select xxx as MYALIAS FROM T)
T2 as (select yyy from T1)
SELECT T2.ID,
MAX(MYALIAS) AS MAX_ALIAS,
T.AN_ALIAS
FROM T2
WHERE MAX_ALIAS <> T.AN_ALIAS
GROUP BY T2.ID, T.AN_ALIAS
Let's imagine the result as a table named MY_RESULT_TABLE.
I need to MY_RESULT_TABLE join some other columns.
I need to obtain
TEMP_TABLE = MY_RESULT_TABLE + SOME JOINS.
The question is how can I use this MY_RESULT_TABLE?
I tried to do
WITH MY_RESULT_TABLE AS (the code above)... didn't work...
EDIT
My other problem is that I need to insert into MY_TABLE some values from an select from MY_RESULT_TABLE...
INSERT INTO MY_TABLE_TO_INSERT ...
SELECT a b c FROM MY_RESULT_TABLE
It should work as you've detailed, just remember to separate each CTE with a comma.
Edit You can use CTE's for INSERTs and UPDATEs as well. Updated for insert.
;
WITH T1 AS
(
SELECT xxx
AS MYALIAS FROM T
),
T2 AS
(
SELECT yyy
FROM T1
),
MY_RESULT_TABLE AS
(
SELECT T2.ID,
MAX(MYALIAS) AS MAX_ALIAS,
T.AN_ALIAS
FROM T2
WHERE MAX_ALIAS <> T.AN_ALIAS
GROUP BY T2.ID, T.AN_ALIAS
)
INSERT INTO MY_TABLE_TO_INSERT(col1, col2, col3, ...)
SELECT ID, MAX_ALIAS, xyz.OtherColumnsHere
FROM MY_RESULT_TABLE
INNER JOIN xyz on ...
Related
recently i gave an interview where the question was
suppose there are two tables in database.
Table T1 has a column named "name" in it and few other columns
Table T2 also has a column name "name" and few other columns
suppose table T1 has values in name column as
[n1,n2,n3,n4,n5]
and values in the "name" column of table T2 are
[n2,n4]
then output should be
[n1,n3,n5] as n2 and n4 are common in both tables
we needs to find the list of names which are not common in both the tables.
The solution that i provided him was using join in the below form
select name from table1 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
UNION
select name from table2 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
But he said there is still a better solution. I was not able to come up with any different and more efficient solution. What is the other efficient way to get the list of names if there is any?
If the NAME column does not have NULL values, there is also
select distinct(coalesce(a.name, b.name)) name
from table1 a
full join table1 b on a.name = b.name
where a.name is null or b.name is null
(Corrected WHERE condition, sorry...)
Use FULL OUTER JOIN:
SELECT DISTINCT(COALESCE(t1.NAME, t2.NAME)) AS NAME
FROM TABLE1 t1
FULL OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL OR
t2.NAME IS NULL
A FULL OUTER JOIN is similar to a LEFT OUTER JOIN unioned with a RIGHT OUTER JOIN - it returns rows where data exists in the first table but not the second, or where it data exists in the second table but not the first. You could get the same effect by using
SELECT t1.NAME
FROM TABLE1 t1
LEFT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t2.NAME IS NULL
UNION
SELECT t2.NAME
FROM TABLE1 t1
RIGHT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL
and in fact the above is what you'd need to do if you were using a database which doesn't support the FULL OUTER JOIN syntax (e.g. MySQL, the last time I looked).
See this dbfiddle
Union the tables and return the values that don't have a count of 2:
create table t1 (
c1 int
);
create table t2 (
c1 int
);
insert into t1 values ( 1 );
insert into t1 values ( 3 );
insert into t2 values ( 2 );
insert into t2 values ( 3 );
commit;
select c1 only_in_one_table
from (
select 'T1' t, c1 from t1
union
select 'T2' t, c1 from t2
)
group by c1
having count(*) <> 2;
ONLY_IN_ONE_TABLE
1
2
I'm not a fan of not in with subqueries, because it behaves unexpectedly with null values. And the person asking would have to explain what "better" means. Your version is actually reasonable.
I might be inclined to approach this using aggregation:
select name
from ((select distinct name, 1 as in_table1, 0 as in_table2
from table1
) union all
(select distinct name, 0 as in_table1, 0\1 as in_table2
from table2
)
) t
group by name
having max(in_table1) <> max(in_table2);
In a real world case, you would probably have a separate table with all names. If so:
select n.*
from names n
where (not exists (select 1 from table1 t1 where t1.name = n.name) and
exists (select 1 from table2 t2 where t2.name = n.name
) or
(exists (select 1 from table1 t1 where t1.name = n.name) and
not exists (select 1 from table2 t2 where t2.name = n.name
);
This is usually the fastest approach because it does not involve any aggregation or duplicate removal.
If you want to use SET operator then find the solution as below:
CREATE TABLE TABLE1(NAME VARCHAR2(100));
CREATE TABLE TABLE2(NAME VARCHAR2(100));
INSERT INTO TABLE1 VALUES('A');
INSERT INTO TABLE1 VALUES('B');
INSERT INTO TABLE1 VALUES('C');
INSERT INTO TABLE2 VALUES('A');
INSERT INTO TABLE2 VALUES('B');
INSERT INTO TABLE2 VALUES('D');
SELECT
NAME
FROM
(
SELECT
NAME
FROM
TABLE1
UNION
SELECT
NAME
FROM
TABLE2
)
WHERE
NAME NOT IN (
SELECT
NAME
FROM
TABLE1
JOIN TABLE2 USING ( NAME )
);
Cheers!!
Yet another possible solution:
Find those that are in the first table but not in the second table using the MINUS operator (which is Oracle's implementation of the standard EXCEPT). Then UNION that with those that are in the second but not in the first.
(
select name
from t1
minus
select name
from t2
)
union all
(
select name
from t2
minus
select name
from t1
);
Given this setup:
create table t1
(
name varchar(10)
);
insert into t1 values ('Arthur');
insert into t1 values ('Zaphod');
create table t2
(
name varchar(10)
);
insert into t2 values ('Tricia');
insert into t2 values ('Zaphod');
This returns:
NAME
------
Arthur
Tricia
select id from((select id from table1)
union all
(select id from table2)) as t1
group by id having count(id)=1
Using the basic set operations the following query should work.
(
select name from table1
union all
select name from table2
)
minus
(
select name from table1
intersect
select name from table2
)
;
Regards
Akash
In the table1 I have 1421144 rows and table2 has 1421134 rows.
I tried this query, but I don't get any rows returned.
select table1.ID
from table1
where ID not in (select ID from table2)
I have also used this query:
select ID from table1
except
select ID from table2
But I don't get any rows. Please help me, if the table1 has duplicates how can I get those duplicates?
Assuming ids are unique, you can use full outer join in either database:
select coalesce(t1.id, t2.id) as id,
(case when t1.id is null then 'T2 only' else 'T1 only' end)
from t1 full outer join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
It is quite possible that the two tables have the same sets of ids, but there are duplicates. Try this:
select t1.id, count(*)
from t1
group by t1.id
having count(*) > 1;
and
select t2.id, count(*)
from t2
group by t2.id
having count(*) > 1;
If you have duplicates, try:
WITH Dups AS(
SELECT ID, COUNT(ID) OVER (PARTITION BY ID) AS DupCount
FROM Table1)
SELECT *
FROM Dups
WHERE DupCount > 1;
If you need to delete the dups, you can use the following syntax:
WITH Dups AS(
SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) AS DupCount
FROM Table1)
DELETE FROM Dups
WHERE DupCount > 1;
Obviously, however, check the data before you run a DELETE statement you got from a random on the internet. ;)
I Guess u have data type mismatch between 2 tables, cast them to integers and try your first query
select table1.ID from table1
where cast(ID as int) not in (select cast(ID as int) from table2)
If you have stored in a different format than int, cast them to varchar and
try with this datatype.
Not in takes longer to execute, use left join instead
select t1id from
(
select t1.id t1Id, t2.Id t2Id from table1 left join table2
on cast(t1.id as int) = cast(t2.id as int)
) x where t2Id is null
I have a complex stored procedure that is collecting data from many tables and inserting it into MyTable. It inserts over 1.5 M records.
What would be the most efficient way to create sequential ID number when populating MyTable
The structure of the table looks like this:
IF OBJECT_ID ('MyTable', 'U') IS NOT NULL
DROP TABLE MyTable;
SELECT *
INTO MyTable
FROM
(SELECT
col1, col2, col3
FROM
Table1
INNER JOIN
Table2 ON...
INNER JOIN
Table3 ON...
INNER JOIN
Table4 ON...
WHERE
Condition1,
Condition2) T
SELECT ID = IDENTITY(INT, 1, 1),* INTO MyTable FROM (
SELECT
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1,
Condition2
) T
ID = IDENTITY(INT, 1, 1) will create an identity ID that auto increments, i didnt test the code
I think simple row_number() is helpfull as below:
IF OBJECT_ID ('MyTable', 'U') IS NOT NULL
DROP TABLE MyTable;
SELECT * INTO MyTable FROM (
SELECT
RowNum = Row_Number() over (order by (Select NULL)) --Instead you can generate based on any column in the table
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1,
Condition2
) T
As Gabri demonstrated, you can use IDENTITY with a SELECT INTO statement. This will make that column and IDENTITY column. If you don't want it to be an IDENTITY column you can use ROW_NUMBER; this will work on any SQL 2005+ system.
SELECT ID = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), *
INTO MyTable FROM
(
SELECT
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1, Condition2
) T;
I'm doing something like:
SELECT T1.NAME, T2.DATE
FROM T1
INNER JOIN
(
SELECT * FROM OTHERTABLE
) AS T2 ON T2.USERID = T1.USERID
Which works, but if I query the alias table, I get an error saying that T2 is an invalid object name.
Example:
SELECT
T1.NAME,
T2.DATE,
CASE
WHEN EXISTS (SELECT TOP 1 1 FROM T2 WHERE T2.THISFIELD = T1.THISFIELD) THEN 'HELLO'
ELSE 'BYE'
END AS COMMENT -- THIS ALSO FAILS
FROM T1
INNER JOIN
(
SELECT * FROM OTHERTABLE
) AS T2 ON T2.USERID = T1.USERID
WHERE (SELECT COUNT(*) FROM T2) > 0
I thought that's what I did, "create" T2. Is there any way I can use T2 like such ?
My goal is to scrape all the related data from OTHERTABLE once because I'll have many CASE in the SELECT clause depending whether data exists in T2 or not. I don't want to do EXISTS for every field since that'll launch a new query in a huge table everytime.
Your query using a sub-query of SELECT * FROM OTHERTABLE which doesn't make sense. You can modify it like;
SELECT
T1.NAME,
T2.DATE,
...
FROM T1
JOIN OTHERTABLE T2 ON T2.USERID = T1.USERID
WHERE (SELECT COUNT(*) FROM OTHERTABLE ) > 0
You cannot use a sub-query multiple times in the same query. Instead use a Common Table Expression (CTE) for that purpose. T2 is a CTE in the following example.
;WITH T2 AS
(
SELECT UserId, col1, col2, [Date]
FROM OtherTable
)
SELECT T1.NAME, T2.DATE
FROM T1
JOIN T2 ON T2.USERID = T1.USERID
WHERE (SELECT COUNT(*) FROM T2) > 0
How can I prevent inner SELECT from returning NULL (when matches no rows) and force query to fail.
INSERT INTO tt (t1_id, t2_id) VALUES (
(SELECT id FROM t1 WHERE ...),
(SELECT id FROM t2 WHERE ...)
);
Side question: is there better way form this query (t1_id, t2_id are foreign keys, but might be NULL) ?
How about something like:
INSERT INTO tt (t1_id, t2_id)
SELECT t1.id, t2.id FROM t1, t2 WHERE ...
Just make sure the SELECT returns exactly what you want to INSERT - so if it's possible for t1.id and t2.id to be NULL then include the relevant clause in your WHERE condition (... AND t1.id IS NOT NULL AND t2.id IS NOT NULL ...).
You may also prefer to use SELECT DISTINCT if there's a chance of duplicate rows appearing.
Edit: If you need 2 IDs from different rows of the same table:
SELECT t1.id, t2.id FROM some_table AS t1, some_table AS t2
WHERE ...
INSERT INTO tt (t1_id, t2_id) VALUES (
(SELECT id FROM t1 WHERE ...),
(SELECT id FROM t2 WHERE ...)
)
WHERE EXISTS (SELECT id FROM t1 WHERE ...)
AND (SELECT id FROM t2 WHERE ...)
It may seem awkward and redundant but any SQL executor worth its salt won't execute each part twice.
Alternatively if t1 and t2 are related somehow:
INSERT INTO tt (t1_id, t2_id)
SELECT t1.id, t2.id
FROM t1
JOIN t2 ON ...
WHERE ...
This can be enhanced and used as given below
INSERT INTO tt (t1_id, t2_id)
select distinct t1.id,t2.id
from t1,t2
where t1.id=t2.id
and t1.id is not null
and t2 id is not null
);