Inserting values in one field from numerous fields in SQL - mysql

I have large table, with around 200 fields. Around a 100 of those fields are to be mapped to one field when creating a dimension table from it. The problem is I have to add the values of those 100 fields one-by-one through like a 100 insert statements. Is there like a loop or something with which i can achieve this more efficiently?
Here's an example of the code:
insert into DimTableA(visit_no, patient, facility, icd9, icd9_flag, ip_op)
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_18,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient'),
from svch_dischs3_s D3, svch_diags_s D
insert into DimTableA(visit_no, patient, facility, icd9, icd9_flag, ip_op)
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_19,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient'),
from svch_dischs3_s D3, svch_diags_s D
insert into DimTableA(visit_no, patient, facility, icd9, icd9_flag, ip_op)
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_20,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient'),
from svch_dischs3_s D3, svch_diags_s D;
......... and so on
The only field name that changes is the 'icd9' input( i.e D.final_diagnosis_18, final_diagnosis_19, final_diagnosis_20 ....)
Any help would be really appreciated, lads. :)

You could unpivot those columns using a cross join to a fixed set of numbers like this:
insert into DimTableA (
visit_no,
patient,
facility,
icd9,
icd9_flag,
ip_op
)
select
D.registration,
D3.med_number,
D3.Hosp_Id,
case N.number
when 1 then D.final_diagnosis_18
when 2 then D.final_diagnosis_19
when 3 then D.final_diagnosis_20
...
end,
'd',
IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient')
from
svch_dischs3_s D3,
svch_diags_s D,
(
select 1 as number union all
select 2 union all
select 3 union all
... /* up to the number of columns to unpivot */
) N
You could create and populate a persistent numbers table instead of the inline view and use the necessary subset of that table in your query. In that case the query would change like this
...
from
svch_dischs3_s D3,
svch_diags_s D,
numbers N
where N.number between 1 and … /* the number of columns to unpivot */

You could try running a single INSERT with a UNION in the sub select.
Your current SQL has a Cartesian join in it so I am going to take a guess that you are missing a join somewhere. Anyway, this should give you an idea of what I am driving at:
insert into DimTableA(visit_no, patient, facility, icd9, icd9_flag, ip_op)
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_18,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient')
from svch_dischs3_s D3, svch_diags_s D
-- where D3.???? = D.????
union
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_19,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient')
from svch_dischs3_s D3, svch_diags_s D
-- where D3.???? = D.????
union
select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_20,'d',IF(D3.Admit_Type in(1,2,3),'Inpatient','Outpatient')
from svch_dischs3_s D3, svch_diags_s D
-- where D3.???? = D.????;
Here is a more theoretical example:
create table dimTable
(id int unsigned not null default 0,
field varchar(50)
);
create table sourceTable
(id int unsigned not null default 0,
field1 varchar(50),
field2 varchar(50),
field3 varchar(50),
field4 varchar(50),
field5 varchar(50)
);
insert into sourceTable (id,field1,field2,field3,field4,field5) values (1,"hello","these","are","some","values");
insert into sourceTable (id,field1,field2,field3,field4,field5) values (2,"hello2","these2","are2","some2","values2");
insert into sourceTable (id,field1,field2,field3,field4,field5) values (3,"hello3","these3","are3","some3","values3");
insert into sourceTable (id,field1,field2,field3,field4,field5) values (4,"hello4","these4","are4","some4","values4");
insert into sourceTable (id,field1,field2,field3,field4,field5) values (5,"hello5","these5","are5","some5","values5");
insert into dimTable (id, field)
select id,field1 from sourceTable
union
select id,field2 from sourceTable
union
select id,field3 from sourceTable
union
select id,field4 from sourceTable
union
select id,field5 from sourceTable;
select *
from dimTable;
Hope it helps!

A stored procedure would solve your problem. You may only require to pass field values to be inserted and the suffix to the D.final_diagnosis_ field.
An example code snippet is shown below:
drop procedure if exists proc_insert_icd9;
delimiter //
create procedure proc_insert_icd9( final_diagnosis_suffix int )
begin
declare suffixId int;
declare sql_insert_str varchar( 255 );
declare sql_select_str varchar( 255 );
declare sql_temp varchar( 255 );
set suffixId = final_diagnosis_suffix;
set sql_insert_str = 'insert into DimTableA(visit_no, patient, facility, icd9, icd9_flag, ip_op) ';
set sql_select_str = concat( 'select D.registration, D3.med_number, D3.Hosp_Id, D.final_diagnosis_', suffixId, ', ''d'', IF(D3.Admit_Type in(1,2,3), ''Inpatient'', ''Outpatient'' ) from svch_dischs3_s D3, svch_diags_s D' );
select concat( sql_insert_str, sql_select_str ) into #sql_temp;
prepare stmt from #sql_temp;
execute stmt;
end;
//
delimiter ;
Now try calling the procedure that many number of times you require with correct suffix value for final_diagnosis field as parameter.
Example:
call proc_insert_icd9( 18 );
call proc_insert_icd9( 19 );
Note: You can modify procedure to include
more input parameters to handle a where clause, etc..
a where clause to the select statement.

Related

Pre populate Sql data based on Enums or Constants

I am trying to fill db pre populated data from sql script where I have two type of constants or enums.
Platform: DG, NK
Department : KK, TG, LO, NP, UI, BG, ED, CC.
Task: To generate a sequential number using procedural loop and for each combination using above value we need to generate key and put in data base with count or sequence value.
Database columns are based on JPA abstract entity:
id, created_by, created_at, status, updated_by, updated_at, uuid, count, category_key
Now single row would be one combination which is formed using this pattern,
Department_Platform_SequenceNumber :: example => KK_DG_1,....KK_DG_10000, KK_NK_1,....KK_NK_10000
This is for 10k entries for 10k sequence of each combinations. It follows for other as well.
Approach:
DROP PROCEDURE KeyGeneration;
DELIMITER $$
CREATE PROCEDURE LoopDemo()
BEGIN
DECLARE x INT;
DECLARE dep VARCHAR(10);
DECLARE plat VARCHAR(10);
DECLARE str VARCHAR(30);
SET x = 1;
SET dep = 'KK'; # help to initialize enums or constants
SET plat = 'DG'; # help to initialize enums or constants
count_val: LOOP
IF x=10000 THEN
LEAVE count_val;
END IF;
SET str = CONCAT(dep,'_',plat,'_',x);
insert into counter_key values(id, created_by, created_at, status, updated_by, updated_at, uuid, x, str);
SET x = x + 1;
END LOOP;
END$$
DELIMITER ;
call LoopDemo();
but this is wrong since what I want is that atleast id to be updated if possible created_at and other fields as well also the loop will return last value I guess I want to get each value.
TABLE COLUMNS UPDATED
UPDATED: id, count, counter_key, status
#Akina answer applied as per my new table but syntax error
WITH RECURSIVE
number AS ( SELECT 1 number
UNION ALL
SELECT number + 1 FROM cte WHERE number < 10000 ),
platform AS ( SELECT 'DG' platform
UNION ALL
SELECT 'NK' ),
department AS ( SELECT 'KK' department
UNION ALL
SELECT 'TG'
UNION ALL
SELECT 'LO'
UNION ALL
SELECT 'NP'
UNION ALL
SELECT 'UI'
UNION ALL
SELECT 'BG'
UNION ALL
SELECT 'ED'
UNION ALL
SELECT 'CC' )
INSERT INTO counter_key
SELECT null, number, CONCAT_WS('_', department, platform, number), 1
FROM department
CROSS JOIN platform
CROSS JOIN number;
WITH RECURSIVE
number AS ( SELECT 1 number
UNION ALL
SELECT number + 1 FROM cte WHERE number < 10000 ),
platform AS ( SELECT 'DG' platform
UNION ALL
SELECT 'NK' ),
department AS ( SELECT 'KK' department
UNION ALL
SELECT 'TG'
UNION ALL
SELECT 'LO'
UNION ALL
SELECT 'NP'
UNION ALL
SELECT 'UI'
UNION ALL
SELECT 'BG'
UNION ALL
SELECT 'ED'
UNION ALL
SELECT 'CC' )
INSERT INTO counter_key
SELECT #id, #created_by, #created_at, #status, #updated_by, #updated_at, #uuid, #x,
CONCAT_WS('_', department, platform, number)
FROM department
CROSS JOIN platform
CROSS JOIN number;
where #id, #created_by, #created_at, #status, #updated_by, #updated_at, #uuid, #x must be replaced with literal values taken from somewhere.

Operand Should Contain 1 Column(s), Trying to generate volunteer data

I can't seem to troubleshoot my problem.
My stored procedure:
CREATE DEFINER=`myschoolusername`#`%` PROCEDURE `generate_volunteers`(in nfolks int)
BEGIN
set #i=0;
while #i < nfolks do
insert into Volunteer(firstname, lastname, dateofbirth)
values (((floor(1+(rand()*(4-1))), "Fred", "Wang", "Fatimah", "Marcella")),
((floor(1+(rand()*(3-1))), "Kaser", "Fang", "Kumar")),
DATE_ADD('1965-01-01', INTERVAL rand()*200000 DAY));
set #i = #i+1;
end while;
END
Additionally, here is my volunteer table in my MYSQL script:
drop table if exists Volunteer;
create Table Volunteer(
member_num int not null auto_increment primary key,
firstname varchar(20) not null,
lastname varchar(20) not null,
dateofbirth date not null
);
I am trying to insert 500 lines into this table, however error 1305 is coming up.
Any help is heavily appreciated, I am quite unsure of where to go from this point.
This logic doesn't do anything:
(floor(1+(rand()*(4-1))), "Fred", "Wang", "Fatimah", "Marcella"))
Although not the most efficient, this should be fine for 500 rows:
insert into Volunteer(firstname, lastname, dateofbirth)
select f.firstname, l.lastname,
DATE_ADD('1965-01-01', INTERVAL rand()*200000 DAY)
from (select 'Fred' as firstname union all
select 'Wang' union all
select 'Fatimah' union all
select 'Marcella'
) f cross join
(select 'Kaser' as lastname union all
select 'Fang' union all
select 'Kumar'
) l
order by rand()
limit 1;
I think you are actually trying to write:
insert into Volunteer(firstname, lastname, dateofbirth)
select elt(floor(rand() * 4) + 1,
'Fred', 'Wang', 'Fatimah', 'Marcella'
) as firstname,
elt(floor(rand() * 3) + 1,
'Kaser', 'Fang', 'Kumar'
) as lastname,
DATE_ADD('1965-01-01', INTERVAL rand()*200000 DAY);

Return Value from sql commands

I am currently using the SQL command
Select * from where name='john'
Is it possible to return 20 no matter the query, for example
Select * from where name='john' or return = 20
EDIT
If you have an oracle database you can do something like that:
SELECT *
FROM dual
WHERE 1=0
UNION
SELECT '20'
FROM dual;
check my answer
if exists (Select * from item where ItemName='ABC Daycare1')
begin
Select * from item where ItemName='ABC Daycare1'
end
else
select '20'
Try running this. This should return the top result (which is never 20 due to the custom sort) and then when the name doesn't match a value it returns 'Mark' and 20
SQL
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
CREATE TABLE #temp (id int NOT NULL, name varchar(255) NOT NULL)
INSERT INTO #temp (id, name) VALUES (88,'John')
INSERT INTO #temp (id, name) VALUES (20,'Mark')
SELECT TOP 1
*
FROM #temp
WHERE (name = 'Mark' OR name = 'John')
ORDER BY (
CASE
WHEN id = 20 THEN 0 ELSE 1
END) DESC
MySQL - MySQL fiddle
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
CREATE TABLE #temp (id int NOT NULL, name varchar(255) NOT NULL)
INSERT INTO #temp (id, name) VALUES (88,'John')
INSERT INTO #temp (id, name) VALUES (20,'Mark')
SELECT
*
FROM temp
WHERE (name = 'Mark' OR name = 'John')
ORDER BY (
CASE
WHEN id = 20 THEN 0 ELSE 1
END) DESC
LIMIT 1

Create trigger to increase value when found duplicate

I need to make trigger to increase the 2nd digit when the new value found to be a duplicate.
For Instance, I have a unique filed with 10 digits value. I want when someone insert same number it increase the second left digit like 0100012345. How I can do that? Thank you.
FirstName LastName Code
Houssam Salim 0100012345 to be 0200012345
Try this
I have found a solution with instead off trigger
'/*
CREATE TABLE [Employee1]
(
[id] VARCHAR(20) PRIMARY KEY,
[name] VARCHAR(50)
)
CREATE TRIGGER AutoIncrement_Trigger
ON [Employee1]
instead OF INSERT
AS
BEGIN
DECLARE #ch CHAR
DECLARE #num INT
IF EXISTS (SELECT 1
FROM Employee1 e
JOIN inserted i
ON i.id = e.id)
BEGIN
SET #num=(SELECT max(CONVERT(INT, substring(e.id, 1, 2))) + 1
FROM employee1 e
JOIN inserted i
ON substring(e.id, 3, len(e.id)) = substring(i.id, 3, len(i.id)))
INSERT INTO [Employee1]
(id,
name)
SELECT '0' + CONVERT(VARCHAR(10), #num)
+ substring(i.id, 3, len(i.id)),
e.name
FROM Employee1 e
JOIN inserted i
ON i.id = e.id
END
ELSE
BEGIN
INSERT INTO [Employee1]
(id,
name)
SELECT inserted.id,
inserted.name
FROM inserted
END
END
*/
INSERT INTO [Employee1]
VALUES ('0100012345',
'John')
SELECT *
FROM [Employee1]
INSERT INTO [Employee1]
VALUES ('0100012345',
'John')
SELECT *
FROM [Employee1]
'

How can I do this Query on SQL Server 2008 without TSQL

I'm trying to make a query but I don't know how to do it. I'm a newbie in SQL querying, so please be patient.
Here is what I have:
select
count(*), sum(time), 'peter'
from
(select *
from ACTUATION
where OPERATOR != 'peter'
and team in (select eq1.name
from TEAMWORKS eq1
where operator1 = 'peter'
or operator2 = 'peter'
or operator3 = 'peter'
or operator4 = 'peter'
or operator5 = 'peter'
or operator6 = 'peter'
or operator7 = 'peter' )) as a
This works OK, but I need to do it for every operator in the table operators and don't know how to do it.
I've tried several subqueries and groups by, but I can not make it work properly.
Kind regards
EDIT:
Let's say I have this DataBase:
create table TEAMWORKS
(
operator1 varchar(50),
operator2 varchar(50),
operator3 varchar(50),
operator4 varchar(50),
operator5 varchar(50),
operator6 varchar(50),
operator7 varchar(50),
name varchar(50)
)
insert into TEAMWORKS (operator1,operator2,name) values ('Peter', 'Paul', 'Pe-Pa')
insert into TEAMWORKS (operator2,operator3,name) values ('Peter', 'John', 'Pe-Jo')
insert into TEAMWORKS (operator1,operator4,name) values ('John', 'Paul', 'Jo-Pa')
insert into TEAMWORKS (operator5,operator6,name) values ('John', 'Peter', 'Jo-Pe')
create table OPERATORS
(
name varchar(50),
surname varchar(50)
)
insert into OPERATORS (name,surname) values ('Peter', 'Font')
insert into OPERATORS (name,surname) values ('Paul', 'Bridges')
insert into OPERATORS (name,surname) values ('John', 'Oldfield')
create table ACTUATION
(
ID int,
time int,
operator varchar(50),
team varchar(50),
description varchar(999)
)
insert into ACTUATION (ID,time,operator,team,description) values (1,30,'Peter', '','Pick flowers')
insert into ACTUATION (ID,time,operator,team,description) values (2,15,'Paul', '','Throw flowers')
insert into ACTUATION (ID,time,operator,team,description) values (3,30,'Peter', 'Jo-Pe','Pick stones')
insert into ACTUATION (ID,time,operator,team,description) values (4,5,'John', 'Jo-Pe','Throw stones')
insert into ACTUATION (ID,time,operator,team,description) values (5,15,'Paul', 'Jo-Pa','Throw tables')
insert into ACTUATION (ID,time,operator,team,description) values (6,30,'Peter', 'Pe-Pa','Pick tables')
And I need to get the time used by Every operator in table OPERATORS where he is not the main operator in Table ACTUATIONS, but part of a TEAM in the ACTUATIONS.
In the given example, I would like to get as result:
Operator #Actuations (count) Time(sum) 'Origin (only for clarifying, list not needed)
Peter 1 5 'from actuation #4
Paul 1 30 'from actuation #6
John 2 45 'form actuations #3 and #5
Hope now it's more clear
EDIT 2:
You have a working example here: http://sqlfiddle.com/#!3/91373/6/0
That's the desired result, but obviously I would not be able to use unions as I would not know the Operators.
Edit:
After OP having altered the question, here is a working query for your example:
select top 1000
o.name
, count(1)
, sum(a.time)
from OPERATORS o
left join (
select
unpvt.Operator
, unpvt.ColName
, unpvt.name
from
(select name, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from TEAMWORKS) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt
) tw on o.name = tw.Operator
left join ACTUATION a on a.team = tw.name
where a.operator != o.name
group by o.name
This returns your decired result :)
Old Post:
I don't know the structure of the database, but I've had a go at guessing.
Firstly, i create to temporary tables in T-SQL - this is done for testing.
I've previously been down-voted for using temporary tables without descriptions in answers on SO for being to complicated, so please ask if you don't understand
declare #ACTUATION table(
time datetime default getdate()
, Operator varchar(8)
, Workteam varchar(8)
)
insert into #ACTUATION (Operator, Workteam)
select 'Gunnar', 'Peter'
union all select 'Peter', 'Gunnar'
We also need the table Teamworks:
declare #TEAMWORKS table(
time datetime default getdate()
, sometext varchar(32)
, operator1 varchar(8)
, operator2 varchar(8)
, operator3 varchar(8)
, operator4 varchar(8)
, operator5 varchar(8)
, operator6 varchar(8)
, operator7 varchar(8)
)
insert into #TEAMWORKS(sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7)
select 'Blah Blah', 'Gunnar', 'Jack', 'Sam', 'Joe', 'Lee', 'Jane', 'Jim'
union all select 'More Blah', 'Bob', 'Sal', 'Phil', 'Clark', 'Jones', 'Sue', 'Peter'
union all select 'Even more Blaah', 'Im', 'Running', 'out of', 'dummy', 'names', 'Peter', 'Gunnar'
What I've done here is to create two "virtual" tables, which only consist as variables. Eg. they are recreated each time the query is run. However, I think that they are a great tool when trying to visualize.
Next step is to UNPIVOT the operators to a more normalized structure.
This is done using the following query:
select
unpvt.time
, unpvt.sometext
, unpvt.Operator
, unpvt.ColName
from
(select time, sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from #TEAMWORKS) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt;
This query should make a great starting point for further joins.
For instance, I assume that this is (partly) the result you want:
select
a.Operator
, count(1)
, max(t.time)
from #ACTUATION a
left join (
select
unpvt.Operator
, unpvt.time
from (
select time, sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from #TEAMWORKS
) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt
) t on a.Workteam = t.Operator
where a.Operator != t.Operator
group by a.Operator