combining resultset obtained by select statements to create a view - sql

I have 4 Select statements for 4 different tables
each Select query gives latest record meeting specified condition
for ex:
Select TOP 1 * from table where column_name = 'something' order by col1 DESC;
Now I have to combine result set of all 4 queries and create a view from combined result set.

create view some_view as
(
(select TOP 1 * from table1 where ....)
UNION ALL
(select TOP 1 * from table2 where ....)
UNION ALL
(select TOP 1 * from table3 where ....)
UNION ALL
(select TOP 1 * from table4 where ....)
)

Some DB's don't let you provide an "order by" clause inside on of the unioned queries.
If you're ordering by col1 desc, it's possible that it's some type of column you can apply min() or max() to.
If that is the case, below could solve your issue (if there aren't too many records, or, if the tables are massive, "col1" and "some_column" are indexed.)
create view some_view as
(
select * from table1
where some_column = 'something'
and col1 = (select max(col1) from table1 where some_column = 'something')
UNION ALL
select * from table2
where some_column = 'something'
and col1 = (select max(col1) from table2 where some_column = 'something')
UNION ALL
select * from table3
where some_column = 'something'
and col1 = (select max(col1) from table3 where some_column = 'something')
UNION ALL
select * from table4
where some_column = 'something'
and col1 = (select max(col1) from table4 where some_column = 'something')
)

Related

Standard SQL - Delete all rows in table 1 that exist in table 2

Table 1 has 101,915 rows and Table 2 has 49,466 where all of them exist in Table 1. Table 1 should have 101,915 - 49,466 = 52,449 after the query.
I tried querying a left join but it returns only 8,269 rows.
SELECT
A.*
FROM
`table1` A
LEFT JOIN
`table2` B
ON
A.interval_uid = B.interval_uid
WHERE
B.interval_uid IS NULL
I used interval_uid as key field but all the repeated rows are identical in both tables.
Try this, If the schema is same, following shall work
INSERT INTO `table3` SELECT
*
FROM
`table1` A
WHERE
A.interval_uid NOT IN (SELECT B.interval_uid FROM `table2` B)
Try using operator EXCEPT for SQL. More info needed find here
SELECT col1, col2, col3,..
FROM table1
EXCEPT
SELECT col1, col2, col3,..
FROM table2;
Insert query as follows:
Insert into table3
SELECT col1, col2, col3,..
FROM table1
EXCEPT
SELECT col1, col2, col3,..
FROM table2;
Note: Columns specified in the query must be equivalent w.r.to., table1 & table2
Please use below query for your desired result..
WITH CTE
AS (
SELECT *
FROM Table_1
EXCEPT
SELECT *
FROM Table_2
)
INSERT INTO Table_3
SELECT *
FROM CTE
Please try this one if you don't want to insert in table 3.
SELECT * FROM Table_1
EXCEPT
SELECT * FROM Table_2
you can use this following logic-
Note: Delete is a risky operation. Please try with test data first.
DELETE table1
FROM table1
INNER JOIN table2 ON Table1.interval_uid = Table2.interval_uid
This is what I wanted:
WITH
unwanted_rows AS (
SELECT
a.*
FROM
`table` a
JOIN (
SELECT
interval_uid,
COUNT(*)
FROM
`table`
GROUP BY
interval_uid
HAVING
COUNT(*) > 1) b
ON
a.interval_uid = b.interval_uid
WHERE
duration IS NULL
)
SELECT
*
FROM
`table` EXCEPT DISTINCT
SELECT
*
FROM
unwanted_rows

Referencing Results of Subquery A in Subquery B of UNION Statement?

I'm trying to solve a problem that requires me to get rows from a table based on the values of other rows from the same table (which I also need in the output).
I'm looking to do the equivalent of the below:
SELECT a.id,a.col1,a.col2 FROM tbl a WHERE col1 = #col
UNION
SELECT b.id,b.col1,b.col2 FROM tbl b WHERE b.col2 IN (SELECT a.col1)
UNION
SELECT c.id,c.col1,c.col2 FROM tbl c WHERE c.col1 IN (SELECT b.col1)
or
(SELECT id,col1,col2 FROM tbl WHERE col1 = #val) a
UNION
SELECT id,col1,col2 FROM tbl b WHERE b.col2 IN (SELECT col1 FROM a)
UNION
SELECT id,col1,col2 FROM tbl c WHERE c.col1 IN (SELECT col1 FROM b)
But both of these are not allowed. Is there some way to achieve this that avoid tediously recursive statements when extended, like the functional statement below:
SELECT * FROM #tbl WHERE col1 = #val
UNION
SELECT * FROM #tbl WHERE col2 = (SELECT col1 FROM #tbl WHERE col1 = #val)
UNION
SELECT * FROM #tbl WHERE col1 = (SELECT col1 FROM #tbl WHERE col2 = (SELECT col1 FROM #tbl WHERE col1 = #val))
fiddle
Is this what you want?
with cte as (
SELECT a.id, a.col1, a.col2
FROM tbl a
WHERE col1 = #col
UNION ALL
SELECT b.id, b.col1, b.col2
FROM tbl b JOIN
cte
ON b.col2 = cte.col1
)
select *
from cte;
You might want select distinct in the outer query or union in the inner one.
The query itself might be more complicated if your relationships have cycles.

Remove inner query in SQL

We have a SQL query which is not written as per the sql guideline. We have to change the query but if we change the logic and remove the inner query then it take to much time to execute. Below is the query:
select col1,
col2,
case
when col1 <> '' then(select top 1
col1
from table1 as BP
where bp.col1 = FD.col1 order by BP.col1)
when col2 <> '' then(select top 1
BP.col2
from table1 as BP
where BP.col2 = FD.col2 order by BP.col2)
else ''
end
from table2 FD
The above query is being used to insert the data into a temp table. The table1 has almost 100 million of data. Is there any way to remove the inline query along with the good performance. We have already created the indexes on table1. Any thought?
Try this
;WITH CTE
AS
(
SELECT
RN = ROW_NUMBER() OVER(ORDER BY COALESCE(T2.col1,T2.col2)),
T2.col1,
T2.col2,
T1Val = COALESCE(T2.col1,T2.col2,'')
FROM table2 T2
LEFT JOIN table1 T1
ON
(
(
ISNULL(T2.col1,'')<>'' AND T1.col1 = T2.col1
)
OR
(
ISNULL(T2.col2,'')<>'' AND T1.col2 = T2.col2
)
)
)
SELECT
*
FROM CTE
WHERE RN = 1
Here is my modest help:
You can already prepare and materialize your subquery1 and subquery2 (Group BY col1 or col2) <-- It will reduce the size of your table 1)
Split your main query (from table2 into 3 different queries)
1 with SELECT .. FROM table2 WHERE col1 <> ''
1 with SELECT .. FROM table2 WHERE col1 = '' AND col2 <> ''
1 with SELECT .. FROM table2 WHERE col1 = '' AND col2 = ''
Use an INNER JOIN with your table created in the first point.
(If you use SSIS you can // and use your inner join table into a Lookup)
If your col1 or col2 use a NVARCHAR(MAX) or a big size, you should have a look to a HashFunction (MD5 for example) and compare Hash instead.
Be sure to have all your indexes
At least if it is not performant, you can try with:
OUTER APPLY (SELECT TOP 1 .. )
Another idea should be:
SELECT col1, col2, col1 AS yourNewCol
FROM table2 T2
WHERE EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col1 = T2.col1)
UNION ALL
SELECT col1, col2, col2 AS yourNewCol
FROM table2 T2
WHERE
NOT EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col1 = T2.col1)
AND EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col2 = T2.col2)
UNION ALL
...
I don't have a clean solution for you, but some ideas.
Let me know if it helps you.
Regards,
Arnaud

How to create sequential ID number when using SELECT * INTO

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;

Return alternate view results if first select returns 0 count

i have quite a long SQL select in a SQL Server view.
However, I want a condition on it, so that if no rows are returned, then it changes the where clause.
An overview of the query is as follows:
SELECT COL1, COL2, COL3, COL4............(15 columns)
FROM TABLE1 inner join TABLE2 ON t1 = t2 (10 tables)
WHERE a = b
So what i want, is if the above query returns 0 rows, then return the results of:
SELECT COL1, COL2, COL3, COL4............(15 columns)
FROM TABLE1 inner join TABLE2 ON t1 = t2 (10 tables)
WHERE a = c
How can I go about this in a view?
Thanks in advance
using a common table expression with not exists()
;with cte as (
/* big query here without where clause of `a = b` or `a = c` */
)
select *
from cte
where a = b
or ( a = c
and not exists (select 1 from cte where a = b)
)
example:
create table t (value int);
insert t values (0),(1),(3),(4),(5);
with cte as (
select *
from t
)
select *
from cte
where value = 2
or ( value = 3
and not exists (select 1 from cte where value=2)
)
returns 3
rextester demo: http://rextester.com/NDC30620
Select both sets and prioritize the one having a = b over the one having a = c using RANK:
SELECT COL1, COL2, COL3, COL4............(15 columns)
FROM (
SELECT RANK() OVER (ORDER BY CASE
WHEN a = b THEN 1
ELSE 2
END) AS rnk,
COL1, COL2, COL3, COL4............(15 columns)
FROM TABLE1 inner join TABLE2 ON t1 = t2 (10 tables)
WHERE a IN (b, c)) AS t
WHERE t.rnk = 1
If some records having a = b do exist, then the query will pick exactly these records, otherwise it will return the ones having a = c.