How do I build a "if-else" SQL query in an INSERT? - sql

I'm trying to copy columns from one SQLite table to another but replacing a boolean (0 or 1) with an enumeration (0 to 9). A given item could be in the table twice - once with each boolean setting. I want to copy the record with a true boolean preferentially, and if one doesn't exist then I want to copy the record with a false boolean.
Is there a way to do that in a single query?
I've included my current approach below, but that requires multiple queries to be run over the same set of tables so would be less efficient than just one query.
// Table schemas
Table1(Col1 text, Col2 text, Col3_bool int, Col4 int, Primary Key(Col1, Col2, Col3))
Table2(Col1 text, Col2 text, Col3_enum int, Col4 int, Primary Key(Col1, Col2, Col3))
// Pseudo code
for (int i = 0; i < 10; ++i)
{
insert into Table2 select Col1, Col2, i, Col4 from Table1 where Col3_bool = 0;
insert or replace into Table2 select Col1, Col2, i, Col4 from Table1 where Col3_bool = 1;
}

As long as you use a single transaction for all queries, it is unlikely that any performance difference is noticeable.
For each Col1/Col2 combination, you want the maximum Col3 value:
SELECT Col1, Col2, MAX(Col3_bool)
FROM Table1
GROUP BY Col1, Col2
You can then use these values to get the desired rows:
SELECT Table1.Col1,
Table1.Col2,
Table1.Col3_bool,
Table1.Col4
FROM Table1
JOIN (SELECT Col1,
Col2,
MAX(Col3_bool) AS Col3_bool
FROM Table1
GROUP BY Col1,
Col2
) USING (Col1, Col2, Col3_bool)
To get ten rows for each of these rows, do a cross join with another table with ten values:
INSERT INTO Table2
SELECT Table1.Col1,
Table1.Col2,
enums.i,
Table1.Col4
FROM Table1
JOIN (SELECT Col1,
Col2,
MAX(Col3_bool) AS Col3_bool
FROM Table1
GROUP BY Col1,
Col2
) USING (Col1, Col2, Col3_bool)
JOIN (SELECT 0 AS i UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9) AS enums

Related

Remove duplicate rows from one column

The problem is:
select (..)
UNION
select (..)
Result is:
Col1, Col2, Col3
Val1 Text1 Data
Val1 Text2 Data
The problem is that i need to save only 1 row of this two. Col2 value is not same at fact, but the same in business logic.
So, how to get result like this:
Col1, Col2,Col3
Val1 Text1 Data
OR
Col1, Col2, Col3
Val1 Text2 Data
Thank you!
You can place the UNION in a subquery and group again
SELECT
Col1,
MIN(Col2),
Col3
FROM (
SELECT Col1, Col2, Col3
FROM table1 t1
UNION ALL
SELECT Col1, Col2, Col3
FROM table2 t2
) t
GROUP BY
Col1,
Col2;
Note the use of UNION ALL rather than UNION, because you are grouping anyway it is not necessary to de-duplicate first.
Hmmm . . . If you want one row per val, then one method is:
with t1 as ( < query 1 here > ),
t2 as ( < query 2 here > )
select t1.*
from t1
union all
select t2.*
from t2
where not exists (select 1 from t1 where t1.val = t2.val);

Oracle SQL Unions error "query block has incorrect number of results columns"

I'm trying to write a query that pulls data from a lot of tables, and has about 20 unions. It's pulling the same information repeatedly, but with more layers each time, to show a sort of tree.
I want to compare the final two columns. I'm using a case to do this, and if I add a case to this query then I get the error "query block has incorrect number of results columns". This seems to be because the final select in the union has an extra column (the compare case).
Is there any way to work around this? I don't want to add the case to each select, as this would add about 15 more columns that I don't want.
Use a sub-query:
SELECT col1,
col2,
CASE
WHEN col1 = 'somevalue'
THEN 'someresult'
ELSE 'otherresult'
END AS col3
FROM (
SELECT col1, col2 FROM table1 UNION ALL
SELECT col1, col2 FROM table2 UNION ALL
SELECT col1, col2 FROM table3
-- ...
);
Or use a sub-query factoring clause:
WITH data ( col1, col2 ) AS (
SELECT col1, col2 FROM table1 UNION ALL
SELECT col1, col2 FROM table2 UNION ALL
SELECT col1, col2 FROM table3
-- ...
)
SELECT col1,
col2,
CASE
WHEN col1 = 'somevalue'
THEN 'someresult'
ELSE 'otherresult'
END AS col3
FROM data;

Concatenate tables (UNION ALL) where one of the tables lacks one of the columns

I am trying to combine three tables in an SQLite database into one new combined table. The three tables have the same column names, but the third table is missing one of the columns. Here is how I am trying to do it:
CREATE TABLE cobmined
AS
SELECT col1, col2, col3
FROM
(
SELECT col1, col2, col3 from table1
UNION ALL
SELECT col1, col2, col3 from table2
UNION ALL
SELECT col1, col2 from table3
) s
;
This works when doing this only on the first two tables, when adding the third table I get the message:
SELECTs to the left and right of UNION do not have the same number of result columns
Is there a way to let SQL ignore the missing column and leave it with NULLs if needed?
Add a NULL value to the third table
CREATE TABLE cobmined
AS
SELECT col1, col2, col3
FROM
(
SELECT col1, col2, col3 from table1
UNION ALL
SELECT col1, col2, col3 from table2
UNION ALL
SELECT col1, col2, null from table3
) s
;
Also, no need for sub-query
CREATE TABLE cobmined
AS
SELECT col1, col2, col3 from table1
UNION ALL
SELECT col1, col2, col3 from table2
UNION ALL
SELECT col1, col2, null from table3
I want to note that you don't need the subquery:
CREATE TABLE combined AS
SELECT col1, col2, col3 from table1
UNION ALL
SELECT col1, col2, col3 from table2
UNION ALL
SELECT col1, col2, NULL from table3;
In addition, you may find that a view is more suitable for your purposes than an actual table.

How do I combine multiple tables into one new table? All of the columns headers are the same and in the same order

I have 12 tables in SQL Server with the exact same columns that I would like to combine into one brand new table. I don't want any data/rows deleted.
Thanks
Use union all:
insert into NewTable(col1, col2)
select col1, col2
from(
select col1, col2 from Table1
union all
select col1, col2 from Table2
union all
select col1, col2 from Table3
.....
)t
You can create new table while selecting like:
select col1, col2
into NewTable
from(
select col1, col2 from Table1
union all
select col1, col2 from Table2
union all
select col1, col2 from Table3
.....
)t

SQL Where Not Exists

I think I have a misunderstanding of how NOT EXISTS work and hope it can be clarified to me.
Here is the sample code I am running (also on SQL Fiddle)
select sum(col1) col1, sum(col2) col1, sum(col3) col3
from (
select 1 col1, 1 col2, 1 col3
from dual tbl1
)
where not exists(
select 2 col1, 1 col2, 1 col3
from dual tbl2
)
I thought that it should return:
1, 1, 1
But instead it returns nothing.
I make this assumption only on the fact that I though NOT EXISTS would give me a list of all the rows in the first query that do not exist in the second query (in this case 1,1,1)
Why does this not work
What would be the appropriate way to make it work the way I am expecting it to?
You are performing an uncorrelated subquery in your NOT EXISTS() condition. It always returns exactly one row, therefore the NOT EXISTS condition is never satisfied, and your query returns zero rows.
Oracle has a rowset difference operator, MINUS, that should do what you wanted:
select sum(col1) col1, sum(col2) col1, sum(col3) col3
from (
select 1 col1, 1 col2, 1 col3
from dual tbl1
MINUS
select 2 col1, 1 col2, 1 col3
from dual tbl2
)
SQL Server has an EXCEPT operator that does the same thing as Oracle's MINUS. Some other databases implement one or the other of these.
EXISTS just returns true if a record exists in the result set; it does not do any value checking. Since the sub-query returns one record, EXISTS is true, NOT EXISTS is false, and you get no records in your result.
Typically you have a WHERE cluase in the sub-query to compare values to the outer query.
One way to accomplish what you want is to use EXCEPT:
select sum(col1) col1, sum(col2) col1, sum(col3) col3
from (
select 1 col1, 1 col2, 1 col3
from dual tbl1
)
EXCEPT(
select 2 col1, 1 col2, 1 col3
from dual tbl2
)
A not exists that includes a select from dual will never return anything. Not exists will exclude rows where the embedded SQL returns something. Normally not exists should be used more like this:
select ... from MY_TABLE A where not exists (select 1 from OTHER_TABLE B where A.SOME_COL = B.SOME_COL)
As using NOT EXISTS is not good approach as it is return only single row so try it with MINUS or EXCEPT
select sum(col1) col1, sum(col2) col1, sum(col3) col3 from ( select 1 col1, 1 col2, 1 col3 from dual tbl1 MINUS select 2 col1, 1 col2, 1 col3 from dual tbl2 )
select sum(col1) col1, sum(col2) col1, sum(col3) col3 from ( select 1 col1, 1 col2, 1 col3 from dual tbl1 ) EXCEPT( select 2 col1, 1 col2, 1 col3 from dual tbl2 )