Using CASE statement to INSERT values into multiple columns in SQLite - sql

I'm trying to use INSERT statement to add values to a few columns in a new table depending on the value of a column in another table. I'm writing in SQLite. I was inspired by this question in sqlite update trigger with multiple if/Case Conditions which used CASE statement in one of the columns, but I would like to apply to all the columns that I'm adding.
The code I have wrote is similar to:
CREATE TABLE machine_info (
MachineType TEXT,
MaxPower INTEGER,
Frequency REAL);
INSERT INTO machine_info (MachineType, MaxPower, Frequency)
VALUES (
CASE WHEN parts.Machine = "A" THEN "Diode", 200, 60
WHEN parts.Machine = "B" THEN "AC", 500, 50
WHEN parts.Machine = "C" THEN NULL, 500, NULL
);
And the error message says Result: near ",": syntax error. Did I wrap the CASE statement at the wrong place?

You may use an INSERT INTO ... SELECT, but you'll need CASE expressions for each of the 3 columns:
INSERT INTO machine_info (MachineType, MaxPower, Frequency)
SELECT
CASE Machine WHEN 'A' THEN 'Diode' WHEN 'B' THEN 'AC' END,
CASE Machine WHEN 'A' THEN 200 WHEN 'B' THEN 500 WHEN 'C' 500 END,
CASE Machine WHEN 'A' THEN 60 WHEN 'B' THEN 50 END
FROM machine_info
WHERE Machine IN ('A', 'B', 'C');

Related

Is there a SQL SELECT to rename one column preserving column order? [duplicate]

here is what I'm trying to do- I have a table with lots of columns and want to create a view with one of the column reassigned based on certain combination of values in other columns, e.g.
Name, Age, Band, Alive ,,, <too many other fields)
And i want a query that will reassign one of the fields, e.g.
Select *, Age =
CASE When "Name" = 'BRYAN ADAMS' AND "Alive" = 1 THEN 18
ELSE "Age"
END
FROM Table
However, the schema that I now have is Name, Age, Band, Alive,,,,<too many>,, Age
I could use 'AS' in my select statment to make it
Name, Age, Band, Alive,,,,<too many>,, Age_Computed.
However, I want to reach the original schema of
Name, Age, Band, Alive.,,,, where Age is actually the computed age.
Is there a selective rename where I can do SELECT * and A_1 as A, B_1 as b? (and then A_1 completely disappears)
or a selective * where I can select all but certain columns? (which would also solve the question asked in the previous statement)
I know the hacky way where I enumerate all columns and create an appropriate query, but I'm still hopeful there is a 'simpler' way to do this.
Sorry, no, there is not a way to replace an existing column name using a SELECT * construct as you desire.
It is always better to define columns explicitly, especially for views, and never use SELECT *. Just use the table's DDL as a model when you create the view. That way you can alter any column definition you want (as in your question) and eliminate columns inappropriate for the view. We use this technique to mask or eliminate columns containing sensitive data like social security numbers and passwords. The link provided by marc_s in the comments is a good read.
Google BigQuery supports SELECT * REPLACE:
A SELECT * REPLACE statement specifies one or more expression AS identifier clauses. Each identifier must match a column name from the SELECT * statement.
In the output column list, the column that matches the identifier in a REPLACE clause is replaced by the expression in that REPLACE clause.
A SELECT * REPLACE statement does not change the names or order of columns. However, it can change the value and the value type.
Select *, Age = CASE When "Name" = 'BRYAN ADAMS' AND "Alive" = 1 THEN 18
ELSE "Age"
END
FROM tab
=>
SELECT * REPLACE(CASE WHEN Name = 'BRYAN ADAMS' AND Alive = 1 THEN 18
ELSE Age END AS Age)
FROM Tab
Actually, there is a way to do this in MySQL. You need to use a hack to select all but one column as posted here, then add it separately in the AS statement.
Here is an example:
-- Set-up some example data
DROP TABLE IF EXISTS test;
CREATE TABLE `test` (`ID` int(2), `date` datetime, `val0` varchar(1), val1 INT(1), val2 INT(4), PRIMARY KEY(ID, `date`));
INSERT INTO `test` (`ID`, `date`, `val0`, `val1`, `val2`) VALUES
(1, '2016-03-07 12:20:00', 'a', 1, 1001),
(1, '2016-04-02 12:20:00', 'b', 2, 1004),
(1, '2016-03-01 10:09:00', 'c', 3, 1009),
(1, '2015-04-12 10:09:00', 'd', 4, 1016),
(1, '2016-03-03 12:20:00', 'e', 5, 1025);
-- Select all columns, renaming 'val0' as 'yabadabadoo':
SET #s = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'val0,', '')
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test' AND TABLE_SCHEMA =
'<database_name>'), ', val0 AS `yabadabadoo` FROM test');
PREPARE stmt1 FROM #s;
EXECUTE stmt1;

use 'case when' after in function

I need to use case when to generate the value range for in function (in DB2).
for example, in below code, I want the columnB in (5,6)
select columnA from tableName where columnB in (
(case
when #variable=1 then '4' // specific number
when #variable=2 then '5' //specific number
when #variable=3 then '7,10' // a value range
end)
)
but tried several times and other similar solutions, never got the expected result
how to do this?
Firstly, In function does not read multiple values inside Case statement. The comma must be after every single value in the range.
Second, you can mention a valid condition in your Question, rather than just 1=1. It's always true so, doesn't make sense.
Example:
1) output of below query gives in (5, 6)
select columnA from tableName where columnB in ((case when #variable=1 then 5 end), 6);
2) this gives only records of columnB = 5, let say the second condition is false.
select columnA from tableName where columnB in ((case when #variable=1 then 5 end), (case when #variable=2 then 6 end));
try Something like this
select columnA from tableName
where columnB in (
select * from table(values 4) tmp(NewCol)
where #variable=1
union all
select * from table(values 5) tmp(NewCol)
where #variable=2
union all
select * from table(values 7, 10) tmp(NewCol)
where #variable=3
)
You cannot have string as value range unless you convert it into rowset. I'm not sure how to do this in DB2, but I have something that should work, since according to documentation, DB2 does have unnest(). There are of course other ways to create rowsets.
SELECT columnA
FROM unnest(array[2,6,8,10], array[7,5,6,28]) --create "temp table" for example purposes
WITH ORDINALITY AS a(columnA, columnB) --alias columns from temp table
WHERE
CASE WHEN true THEN --switch true to some other condition
columnB IN(SELECT * FROM unnest(array[5,6])) --unnest(array[]) will create rowset with 2 rows, each having one column holding integer value
END;
You might need to drop alias from AS a(columnA, columnB) since I'm not sure if it works in DB2 and I have not found live DB2 tester (it is required in PostgreSQL where I tested query).

Rename single column in SELECT * in SQL, select all but a column

here is what I'm trying to do- I have a table with lots of columns and want to create a view with one of the column reassigned based on certain combination of values in other columns, e.g.
Name, Age, Band, Alive ,,, <too many other fields)
And i want a query that will reassign one of the fields, e.g.
Select *, Age =
CASE When "Name" = 'BRYAN ADAMS' AND "Alive" = 1 THEN 18
ELSE "Age"
END
FROM Table
However, the schema that I now have is Name, Age, Band, Alive,,,,<too many>,, Age
I could use 'AS' in my select statment to make it
Name, Age, Band, Alive,,,,<too many>,, Age_Computed.
However, I want to reach the original schema of
Name, Age, Band, Alive.,,,, where Age is actually the computed age.
Is there a selective rename where I can do SELECT * and A_1 as A, B_1 as b? (and then A_1 completely disappears)
or a selective * where I can select all but certain columns? (which would also solve the question asked in the previous statement)
I know the hacky way where I enumerate all columns and create an appropriate query, but I'm still hopeful there is a 'simpler' way to do this.
Sorry, no, there is not a way to replace an existing column name using a SELECT * construct as you desire.
It is always better to define columns explicitly, especially for views, and never use SELECT *. Just use the table's DDL as a model when you create the view. That way you can alter any column definition you want (as in your question) and eliminate columns inappropriate for the view. We use this technique to mask or eliminate columns containing sensitive data like social security numbers and passwords. The link provided by marc_s in the comments is a good read.
Google BigQuery supports SELECT * REPLACE:
A SELECT * REPLACE statement specifies one or more expression AS identifier clauses. Each identifier must match a column name from the SELECT * statement.
In the output column list, the column that matches the identifier in a REPLACE clause is replaced by the expression in that REPLACE clause.
A SELECT * REPLACE statement does not change the names or order of columns. However, it can change the value and the value type.
Select *, Age = CASE When "Name" = 'BRYAN ADAMS' AND "Alive" = 1 THEN 18
ELSE "Age"
END
FROM tab
=>
SELECT * REPLACE(CASE WHEN Name = 'BRYAN ADAMS' AND Alive = 1 THEN 18
ELSE Age END AS Age)
FROM Tab
Actually, there is a way to do this in MySQL. You need to use a hack to select all but one column as posted here, then add it separately in the AS statement.
Here is an example:
-- Set-up some example data
DROP TABLE IF EXISTS test;
CREATE TABLE `test` (`ID` int(2), `date` datetime, `val0` varchar(1), val1 INT(1), val2 INT(4), PRIMARY KEY(ID, `date`));
INSERT INTO `test` (`ID`, `date`, `val0`, `val1`, `val2`) VALUES
(1, '2016-03-07 12:20:00', 'a', 1, 1001),
(1, '2016-04-02 12:20:00', 'b', 2, 1004),
(1, '2016-03-01 10:09:00', 'c', 3, 1009),
(1, '2015-04-12 10:09:00', 'd', 4, 1016),
(1, '2016-03-03 12:20:00', 'e', 5, 1025);
-- Select all columns, renaming 'val0' as 'yabadabadoo':
SET #s = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'val0,', '')
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'test' AND TABLE_SCHEMA =
'<database_name>'), ', val0 AS `yabadabadoo` FROM test');
PREPARE stmt1 FROM #s;
EXECUTE stmt1;

SQL - is it possible to have an if inside the values of an insert

I need to write a script to insert data selected from one table into another. The old table stores a value 'Yes' in one column but I want to insert 1 instead of 'Yes'
Is there any way to do this. In my head this is what I want to do:
insert into new_table (new_col1, new_col2)
values (select from old_table(old_col1, (if old_col2='Yes' then 1 else 0))
First: if you base your insert on a SELECT, the must not use the VALUES clause.
To get a conditional value, use the (ANSI standard) CASE statement:
insert into new_table (new_col1, new_col2)
select old_col1,
case
when old_col2 = 'Yes' then 1
else 0
end
from old_table
An Oracle only more compact form would be the decode() statement (but I'd recommend to use the CASE, because it's more readable and portable to other DBMS as well)
insert into new_table (new_col1, new_col2)
select old_col1,
decode(old_col2, 'Yes', 1, 0)
from old_table
What you are looking for is a CASE statement.
CASE
WHEN old_col2='Yes' then 1
ELSE 0
END

Why does the sql select statement fail?

In the scenario below, the final select from the Combine view fails, any ideas why?
The Subset table does not have a row that corresponds to the one in MasterCodes that wouldn't cast to an integer value.
CREATE TABLE MasterCodes (
ID INT
, Code VARCHAR(10) )
GO
CREATE TABLE Subset (
ID INT )
GO
CREATE VIEW Combine AS
SELECT S.ID
, M.Code
, CAST(M.Code AS INT) IntCode
FROM Subset S
INNER JOIN MasterCodes M ON M.ID = S.ID
GO
INSERT MasterCodes (ID, Code) VALUES (1, '1')
INSERT MasterCodes (ID, Code) VALUES (2, '2')
INSERT MasterCodes (ID, Code) VALUES (3, 'three')
INSERT MasterCodes (ID, Code) VALUES (4, '4')
INSERT Subset (ID) VALUES (1)
INSERT Subset (ID) VALUES (2)
INSERT Subset (ID) VALUES (4)
SELECT * FROM Combine -- 3 rows returned
SELECT * FROM Combine WHERE Code = '2' -- 1 row returned
SELECT * FROM Combine WHERE Code = '3' -- 0 rows returned
SELECT * FROM Combine WHERE IntCode = 2 -- fails, error msg is
Msg 245, Level 16, State 1, Line 15
Conversion failed when converting the varchar value 'three' to data type int.
Environment is Sql2k5 Standard (64-bit) ON Win2k3 Server R2
Probably because in some row, M.Code contains the literal word "three", and the view is trying to cast a non-numeric looking word into an int (you can probably cast "3" into an int, but not "puppy" or "three", etc.).
Edit: Added a comment, but worthwhile to add it here. SQL Server is going to try and execute and join the as efficiently as possible, and it's going try and apply the where clause apparently even before joining.
This makes sense if you consider that VIEWs nowadays work almost fully like a real table. It has to do something SIMILAR to this; otherwise, it will join everything and return all values BEFORE being filtered out.
Hideously expensive.
What I'm not sure about is if the execution plan will show this level of detail.
You're inserting the string "three" into MasterCodes.Code, and your view is attempting to cast this value to an integer. This SQL should give the same error:
select cast("three" as int)
Solution? Replace "three" with "3" in your insert statement.
Because when you try to use IntCode in your condition logic the view try's to cast "three" as an int.
Use isnumeric() with a case statement to create the view
case when isnumeric(field) then
cast(field as int)
else
null
end AS IntCode
If your result set is accurate:
"SELECT * FROM Combine WHERE Code = '2' -- 1 row returned
SELECT * FROM Combine WHERE Code = '3' -- 0 rows returned
SELECT * FROM Combine WHERE IntCode = 2 -- fails, error msg isMsg 245, Level 16, State 1, Line 15Conversion failed when converting the varchar value 'three' to data type int."
then the only time it fails is when you try to compare against IntCode field, it almost seems like it is failing when it tries to put the non-numeric value on the left side of the "IntCode = 2" comparison, because this is the only time it will need to pick up every single value in the code field.
Hope that helps!