SQL insert data dynamic column name from another table - sql

i'm trying to insert data from one table to another with dynamic column name from #array to #array2
error
The multi-part identifier "s.id" could not be bound.
SQL CODE:
DECLARE #Array TABLE
(
id int not null,
dt varchar(12) not null,
ld varchar(16) not null,
val varchar(12) not null,
ty varchar(4) not null,
PRIMARY KEY CLUSTERED (id,dt)
)
DECLARE #Array2 TABLE
(
id int not null,
dt varchar(12) not null,
ld varchar(16) not null,
min varchar(12) null,
mout varchar(4) null,
PRIMARY KEY CLUSTERED (id,dt)
)
INSERT INTO #Array VALUES
('1','2015-11-11','2015-11-11','20:08','min')
,('2','2015-11-11','2015-11-11','20:08','mout')
,('3','2015-11-11','2015-11-11','20:08','min')
,('4','2015-11-11','2015-11-11','20:08','min')
Select * from #Array s
WHERE NOT EXISTS (select s.id,s.dt,s.ld,s.ty from #Array2
WHERE id != s.id AND dt != s.dt)
INSERT INTO #Array2 (id,dt,ld,s.ty) VALUES(s.id,s.dt,s.ld,s.val)
^
dynamic column name from #Array TABLE
here is SQL Fiddle link, thanks.

I would re-write your insert along the lines of:
INSERT INTO #Array2 (id,dt,ld,s.ty)
Select s.id,s.dt,s.ld,s.ty from #Array s
left join #Array2 a2 on a2.id = s.id
where a2.id is null
Your error is coming from the fact that Array2 doesn't have a ty column defined. The fix there is to either put it in there or re-evaluate what you are putting into it. Also, thumbs up for the fiddle link :)
EDIT:
On second reading of your question, do you want to dynamically add that column to array2? If so, then that would require quite a bit of mucking around, and I would try to find another solution. Changing your schema like that on the fly is ill-advised.
EDIT2:
INSERT INTO #Array2 (id,dt,ld,min,mout)
Select
s.id,
s.dt,
s.ld,
case s.ty when 'min' then s.val else '' end,
case s.ty when 'mout' then s.val else '' end
from #Array s
left join #Array2 a2 on a2.id = s.id
where a2.id is null
EDIT3
UPDATE a2
SET
a2.dt = s.dt,
a2.ld = s.ld,
a2.min = case s.ty when 'min' then s.val else '' end,
a2.mout = case s.ty when 'mout' then s.val else '' END
FROM #Array2 a2
LEFT JOIN #Array s ON a2.id = s.id
WHERE s.id IS NOT null

Related

SQL Copy value from relative child cells

I have the following problem, I can't understand how to copy the values present in the line with level 0.1, in the cells of the relative father with level 0.
I would like to copy the values of Field1 and Field2
CREATE TABLE [dbo].[Demo](
[ID] [nvarchar](50) NOT NULL,
[PARENT_ID] [nvarchar](50) NOT NULL,
[FIELD1] [nvarchar](50) NOT NULL,
[FILED2] [nvarchar](50) NOT NULL,
[LVL] [nvarchar](50) NOT NULL
) ON [PRIMARY]
INSERT INTO [dbo].[Demo]
([ID]
,[PARENT_ID]
,[FIELD1]
,[FILED2]
,[LVL])
VALUES
(''
,'1234'
,'value01'
,'value02'
,'0.1')
INSERT INTO [dbo].[Demo]
([ID]
,[PARENT_ID]
,[FIELD1]
,[FILED2]
,[LVL])
VALUES
('1234'
,''
,''
,''
,'0')
I probably wouldn't copy them, but instead use the parent as a default in a query if the child value doesn't override. To make this easier, I would use NULLs rather than empty strings:
SELECT
p.[ID],
COALESCE(c.[FIELD1], p.[FIELD1]) as [FIELD1],
COALESCE(c.[FIELD2], p.[FIELD2]) as [FIELD2],
p.[LVL]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
COALESCE will, if the child field is null, use the parent field instead. If you are certain you want to keep enpty strings instead of nulls you can create an ANSI compatible query with CASE WHEN:
SELECT
p.[ID],
CASE WHEN c.[FIELD1] = '' THEN p.[FIELD1] ELSE c.[FIELD1] as [FIELD1],
CASE WHEN c.[FIELD2] = '' THEN p.[FIELD2] ELSE c.[FIELD2] as [FIELD2],
p.[LVL]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
But if you really want to copy them you can update a set of tables that are joined:
UPDATE c
SET
c.[FIELD1] = p.[FIELD1],
c.[FIELD2] = p.[FIELD2]
FROM
[Demo] p
INNER JOIN [Demo] c ON c.[PARENT_ID] = p.[ID]
Updating/copying creates a bit of a "have to keep doing it to keep them in sync" problem - realistically it's usually better to have the DB do the join as and when it's needed (it's very fast for a trivial operation like this)
Try this:
SELECT C.[ID]
,C.[PARENT_ID]
,ISNULL(NULLIF(P.[FIELD1], ''), C.[FIELD1]) AS [FIELD1]
,ISNULL(NULLIF(P.[FILED2], ''), C.[FILED2]) AS [FILED2]
,C.[LVL]
FROM [dbo].[Demo] C
LEFT JOIN [dbo].[Demo] P
ON C.[PARENT_ID] = P.[ID];

Request with While in SQL Server does not work

Here is my code:
CREATE TABLE IF NOT EXISTS Artfacture
(
N int(6) unsigned NOT NULL,
Code varchar(50) NOT NULL,
Ht Numeric NOT NULL
)
INSERT INTO Artfacture (N, Code, Ht)
VALUES ('1', '1', '10'), ('1', '2', '20'),('1', '3', '30');
CREATE TABLE IF NOT EXISTS Facture
(
N int(6) unsigned NOT NULL,
Ht Numeric NOT NULL
)
INSERT INTO Facture (N, Ht)
VALUES ('1', '60');
CREATE TABLE IF NOT EXISTS Article
(
Code varchar(50) NOT NULL,
Famille varchar(50) NOT NULL
)
INSERT INTO Article (Code, Famille)
VALUES ('1', 'F1'), ('2', 'F2'), ('3', 'F3');
CREATE TABLE IF NOT EXISTS Farticle
(
Designation varchar(50) NOT NULL,
Compte varchar(50) NOT NULL
)
INSERT INTO Farticle (Designation, Compte)
VALUES ('F1', '700000'), ('F2', '710000'), ('F3', '720000');
CREATE TABLE IF NOT EXISTS Ecritures
(
Compte varchar(50) NOT NULL,
Ht numeric NOT NULL
)
My request is a trigger where adding some new rows in Table Facture, it must add rows in Ecritures with the same numbers of rows of Artfacture
declare #piece as nvarchar(50), #code as nvarchar(50)
declare #rowCount int = 0, #currentRow int = 1
select #rowCount = count(*) from ArtFacture where N = #piece;
while (#currentRow <= #rowCount)
begin
set #Code = (select code from ArtFacture where N = #piece)
set #compte = (select Compte from Farticle where Designation = (select Famille from Article where code = #code))
set #Ht = (select ht from ArtFacture where N = #piece)
insert into Ecritures (Compte,Ht)
values (#compte,#Ht)
end
I have a mistake but I do not know where?
You're making the classic mistake of trying to write procedural T-SQL instead of set-based T-SQL which SQL Server is optimised for.
If I follow your logic then the following insert removes the need for a while loop:
insert into Ecritures (Compte, Ht)
select F.Compte, AF.Ht
from Artfracture AF
inner join Article A on A.Code = AF.Code
inner join Farticle F on F.Designation = A.Famille
where N = #piece;
And if you don't want duplicates add a group by:
insert into Ecritures (Compte, Ht)
select F.Compte, AF.Ht
from Artfracture AF
inner join Article A on A.Code = AF.Code
inner join Farticle F on F.Designation = A.Famille
where N = #piece
group by F.Compte, AF.Ht;

Converting strange SQL Server JOIN syntax to MySQL syntax

I have a SQL Server query that I am attempting to port to MySQL, but the JOIN syntax is something that I have never seen used before. The query is from a view designed to measure procedure code usage. What the heck is going on with the JOIN syntax just past T.PatID = P.ID, and the third LEFT OUTER JOIN, and what equivalent syntax can we use in MySQL? It does not like this JOIN syntax at all (disregard the ISNULL and CONVERT SQL Server specific syntax)
SELECT
T.Code
, P.LastName
, P.FirstName
, T.TranDate
, CD.DaysUnits
, T.TranAmt
, TD.FullName AS Provider
, ISNULL(TD.ID, ISNULL(AD.ID, PD.ID)) AS DoctorID
FROM
dbo.Doctors AS PD
INNER JOIN
dbo.Transactions AS T
INNER JOIN
dbo.Patients AS P
ON
T.PatID = P.ID
ON
PD.ID = P.DoctorID
LEFT OUTER JOIN
dbo.Doctors AS TD
ON
T.DoctorID = TD.ID
LEFT OUTER JOIN
dbo.Doctors AS AD
LEFT OUTER JOIN
dbo.Appointments
ON
AD.ID = dbo.Appointments.DoctorID
AND CONVERT(varchar(20), dbo.Appointments.ScheduleDateTime, 8) <> '00:00:00'
ON
T.ApptID = dbo.Appointments.ID
LEFT OUTER JOIN
dbo.ChargeDetails AS CD
ON
T.ID = CD.ChargeTranID
WHERE
(
T.Code IS NOT NULL
)
The SHOW CREATE TABLE are as follows
CREATE TABLE Doctors
(
ID int(10) NOT NULL PRIMARY KEY
, FullName varchar(50) DEFAULT NULL
)
CREATE TABLE Patients
(
LName varchar(50) DEFAULT NULL
, FName varchar(50) DEFAULT NULL
, ID int(10) NOT NULL PRIMARY KEY
)
CREATE TABLE Transactions
(
TranType varchar(2) DEFAULT NULL
, Code varchar(100) DEFAULT NULL
, TranSubType varchar(2) DEFAULT NULL
, Description varchar(2000) DEFAULT NULL
, TranDate datetime
, PatID int(10) DEFAULT NULL
, ID int(10) NOT NULL PRIMARY KEY
, TranAmt decimal(19,4) DEFAULT NULL
, ApptID int(10) DEFAULT NULL
, DoctorID int(10) DEFAULT NULL
)
CREATE TABLE ChargeDetails
(
DaysUnits varchar(50) DEFAULT NULL
-- DaysUnits is just an int ranging from 1 to 2
, ChargeTranID int(10) NOT NULL PRIMARY KEY
)
CREATE TABLE Appointments
(
DoctorID int(10) DEFAULT NULL
, PatientID int(10) DEFAULT NULL
, ScheduleDateTime datetime DEFAULT NULL
, ID int(10) NOT NULL PRIMARY KEY
)
Thank you in advance for your help.
Here is a similar (and simplified) query using the same structure as the first query. The second query moves the joins around to make things easier to read.
set nocount on;
use tempdb;
go
declare #doc table (id int not null);
declare #tran table (id int not null, patid int not null);
declare #patients table (id int not null, docid int not null);
insert #doc (id) values (1);
insert #patients (id, docid) values (25, 1);
insert #tran (id, patid) values (100, 25)
select *
from #doc as pd
inner join #tran as t
inner join #patients as p
on t.patid = p.id
on pd.id = p.docid;
select *
from #tran as t
inner join #patients as p
on t.patid = p.id
inner join #doc as pd
on pd.id = p.docid;
Other things look strange. I don't see a need to join to appointments but I'm not going to spend a lot of time to figure out the logic and the schema. The convert usage seems like a bad way to check for null - unless there is a special "flag" datetime value that is used as the equivalent to null. Again, you need to understand the query, the goal of the query, the schema on which it is based, and how the tables are populated. Quite frankly, this code raises concerns about the quality of the entire system.
.

How can I pull data from multiple sql tables using a join statement

I'm designing a simple in-office ticket system, and would like to include a field for the party responsible for the next action. To do so right this moment I'm thinking of using tableName and tableID as specifiers for the specific responsible party (could be a technician, customer, or third party, all in different tables)
It would be fine to pull that data in and run another select call using the name of the table as a parameter, but the extra data flow slows things down significantly.
Is there a way to use a single join statement to return the details of the party with a column for the table name and one for the individual table id or is there a better way to store the data from multiple potential tables?
You can use left join to achieve your requirement :-
Set Nocount On;
Declare #OfficeTickets Table
(
Id Int Identity(1,1)
,Column1 Varchar(100)
,PartyType Varchar(1)
,TechnicianId Int Null
,CustomerId Int Null
,ThirdPartyId Int Null
)
Declare #OfficeTickets1 Table
(
Id Int Identity(1,1)
,Column1 Varchar(100)
,TableName Varchar(100)
,TableId Int Null
)
Declare #Technician Table
(
Id Int Identity(1,1)
,TechnicianName Varchar(100)
)
Declare #Customers Table
(
Id Int Identity(1,1)
,CustomerName Varchar(100)
)
Declare #ThirdParty Table
(
Id Int Identity(1,1)
,ThirdPartyName Varchar(100)
)
Insert Into #Technician(TechnicianName) Values
('Technician_1')
,('Technician_2')
,('Technician_3')
Insert Into #Customers(CustomerName) Values
('Customer_1')
,('Customer_2')
,('Customer_3')
Insert Into #ThirdParty(ThirdPartyName) Values
('ThirdParty_1')
,('ThirdParty_2')
,('ThirdParty_3')
,('ThirdParty_4')
Insert Into #OfficeTickets(Column1,PartyType,TechnicianId,CustomerId,ThirdPartyId) Values
('ABC','T',3,Null,Null)
,('XYZ','C',Null,2,Null)
,('PUQ','P',Null,Null,4)
Insert Into #OfficeTickets1(Column1,TableName,TableId) Values
('ABC','Technician',3)
,('XYZ','Customers',2)
,('PUQ','ThirdParty',4)
---- taken separate columns for parties
Select ot.Id
,ot.Column1
,t.TechnicianName
,c.CustomerName
,tp.ThirdPartyName
From #OfficeTickets As ot
Left Join #Technician As t On ot.PartyType = 'T' And ot.TechnicianId = t.Id
Left Join #Customers As c On ot.PartyType = 'C' And ot.CustomerId = c.Id
Left Join #ThirdParty As tp On ot.PartyType = 'P' And ot.ThirdPartyId = tp.Id
---- by TableName and TableId
Select ot.Id
,ot.Column1
,t.TechnicianName
,c.CustomerName
,tp.ThirdPartyName
From #OfficeTickets1 As ot
Left Join #Technician As t On ot.TableName = 'Technician' And ot.TableId = t.Id
Left Join #Customers As c On ot.TableName = 'Customers' And ot.TableId = c.Id
Left Join #ThirdParty As tp On ot.TableName = 'ThirdParty' And ot.TableId = tp.Id
output:-

Unexpected result in SELECT CASE WHEN NULL

Schema and data
I have two tables with the following schema and data:
#table1:
create table #table1(
PK int IDENTITY(1,1) NOT NULL,
[TEXT] nvarchar(50) NOT NULL
);
PK TEXT
1 a
2 b
3 c
4 d
5 e
#table2:
create table #table2(
PK int IDENTITY(1,1) NOT NULL,
FK int NOT NULL,
[TEXT] nvarchar(50) NOT NULL
);
PK FK TEXT
1 2 B
2 3 C
Problem
Now, if I select all from #table1 and left join #table2 like this:
select
#table1.PK,
(case #table2.[TEXT] when NULL then #table1.[TEXT] else #table2.[TEXT] end) as [TEXT]
from
#table1
left join
#table2 on #table2.FK = #table1.PK
;
the output are as following:
PK TEXT
1 NULL
2 B
3 C
4 NULL
5 NULL
Question
I expected the result to be:
PK TEXT
1 a <
2 B
3 C
4 d <
5 e <
So why does this happen (or what am I doing wrong) and how can I fix this?
Source code
if (OBJECT_ID('tempdb..#table1') is not null) drop table #table1;
if (OBJECT_ID('tempdb..#table2') is not null) drop table #table2;
create table #table1(PK int IDENTITY(1,1) NOT NULL, [TEXT] nvarchar(50) NOT NULL);
create table #table2(PK int IDENTITY(1,1) NOT NULL, FK int NOT NULL, [TEXT] nvarchar(50) NOT NULL);
insert into #table1 ([TEXT]) VALUES ('a'), ('b'), ('c'), ('d'), ('e');
insert into #table2 (FK, [TEXT]) VALUES (2, 'B'), (3, 'C');
select
#table1.PK,
(case #table2.[TEXT] when NULL then #table1.[TEXT] else #table2.[TEXT] end) as [TEXT]
from
#table1
left join
#table2 on #table2.FK = #table1.PK
;
drop table #table1;
drop table #table2;
From my perspective this is equivalent of
select isnull(table2.text, table1.text) as text from ...
You should check whether a field is null or not by is null, even though your case when is syntactically correct, you should use the other syntactically correct version.
case
when #table2.[TEXT] is null then #table1.[TEXT]
else #table2.[TEXT]
end
The problem is the way you have constructed your CASE statement. Any CASE statement of the form CASE x WHEN NULL THEN... is not going to behave as you might initially expect as you are effectively performing a comparison with NULL, which is always false, in your case resulting in always getting #table2.[TEXT].
I think you'd need to do:
(CASE WHEN #table2.[TEXT] IS NULL THEN #table1.[TEXT] ELSE #table2.[TEXT] END) AS [TEXT]
which is equivalent to COALESCE:
COALESCE(#table2.[TEXT], #table1.[TEXT]) AS [TEXT]