SQL join with previous row from the same group - sql

I have a problem with sql query. I'm trying to create one time script which will put data to table. I have temporary table of new values ordered by date and i'm going to search previous value which have to have the same GroupId, TransactionId and FieldTypeId but ClaimModificationId have to be smaller.
Below i write a script which would be good if not error throwing on line:
where m2.ClaimModificationId < m1.ClaimModificationId
sql does not allow do referer to m1 table. Is there a method to write that condition differently?
create table #modifications (
[ClaimModificationId] INT IDENTITY(1,1),
[GroupId] INT,
[FieldTypeId] INT,
[FieldName] NVARCHAR(255),
[TransactionId] INT,
[NewValue] NVARCHAR(255),
[UserEmail] NVARCHAR(255),
[ModificationDate] DATETIME,
[Action] NVARCHAR(50))
select top 10
m1.[GroupId],
m1.[FieldTypeId],
m1.[FieldName],
m1.[TransactionId],
cm4.[NewValue] as OldValue,
m1.[NewValue],
m1.[UserEmail],
m1.[ModificationDate],
m1.[Action]
from #modifications m1
left join (
select max(m2.ClaimModificationId) as ClaimModificationId, m2.[GroupId], m2.[FieldTypeId], m2.TransactionId
from #modifications m2
where m2.ClaimModificationId < m1.ClaimModificationId
group by m2.GroupId, m2.FieldTypeId, m2.TransactionId) m3
on m3.groupId = m1.GroupId and m3.FieldTypeId = m1.FieldTypeId and m3.TransactionId = m1.TransactionId
LEFT JOIN #modifications cm4 ON m3.ClaimModificationId = cm4.ClaimModificationId

Try with OUTER APPLY:
SELECT TOP 10
m1.[GroupId] ,
m1.[FieldTypeId] ,
m1.[FieldName] ,
m1.[TransactionId] ,
cm4.[NewValue] AS OldValue ,
m1.[NewValue] ,
m1.[UserEmail] ,
m1.[ModificationDate] ,
m1.[Action]
FROM #modifications m1
OUTER APPLY ( SELECT MAX(m2.ClaimModificationId) AS ClaimModificationId ,
m2.[GroupId] ,
m2.[FieldTypeId] ,
m2.TransactionId
FROM #modifications m2
WHERE m2.ClaimModificationId < m1.ClaimModificationId
AND m2.groupId = m1.GroupId
AND m2.FieldTypeId = m1.FieldTypeId
AND m2.TransactionId = m1.TransactionId
GROUP BY m2.GroupId ,
m2.FieldTypeId ,
m2.TransactionId
) m3
LEFT JOIN #modifications cm4 ON m3.ClaimModificationId = cm4.ClaimModificationId

you can try something like this
create table #modifications
(
[ClaimModificationId] INT IDENTITY(1,1),
[GroupId] INT,
[FieldTypeId] INT,
[FieldName] NVARCHAR(255),
[TransactionId] INT,
[NewValue] NVARCHAR(255),
[UserEmail] NVARCHAR(255),
[ModificationDate] DATETIME,
[Action] NVARCHAR(50)
)
INSERT INTO #modifications values(1,1,'field',2,'new val1','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(1,2,'field',2,'val1','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(2,1,'field',3,'val2','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(1,1,'field',2,'val3','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(1,1,'field',2,'val4','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(1,1,'field',2,'val5','email#email.com',GETDATE(),'inserted')
INSERT INTO #modifications values(2,1,'field',3,'val5','email#email.com',GETDATE(),'inserted')
SELECT TOP 10
m1.[GroupId],
m1.[FieldTypeId],
m1.[FieldName],
m1.[TransactionId],
LAG([NewValue]) OVER(PARTITION by GroupId, FieldTypeId, TransactionId ORDER BY ClaimModificationId ASC) as OldValue,
m1.[NewValue],
m1.[UserEmail],
m1.[ModificationDate],
m1.[Action]
from #modifications m1

Related

Replicating rows in a table by the columns

I need to develop a report I create it in excel but it became so heavy that even my PC cannot open it.
Right now I decide to create it with SQL.
The excel input is something like this:
Service_order PENDING_DAYS SERVICE_TYPE ASC code INOUTWTY Part_code1 Part_code2 Part_code3 Part_code4 Part_code5
4182864919 18 CI 3440690 LP GH82-11218A GH96-09406A GH81-13594A GH02-11552A GH02-11553A
4182868153 18 CI 4285812 LP GH97-17670B
4182929636 17 CI 4276987 LP GH97-17260C GH02-10203A
4182953067 16 CI 3440690 LP GH97-17940C
4182954688 16 CI 6195657 LP GH82-10555A GH97-17852A GH81-13071A
4182955036 16 PS 6195657 LP GH97-17940C
and the result using this codes
=HLOOKUP(Sheet3!A$1;Sheet3!$A$1:$F$10000;CEILING((ROW()-ROW(Sheet3!$A$1))/5+1;1);FALSE)"
=OFFSET(WholePart;TRUNC((ROW()-ROW($G$2))/COLUMNS(WholePart));MOD(ROW()-ROW($G$2);COLUMNS(WholePart));1;1)
* WholePart is partCode values.
are like this:
What I want to do is to convert those formula or have an output just like this.
Appreciate it.
My advice is prepare your data in EXCEL and load into normalized tables. Then you can get the result by joining the tables.
create table T1(
Service_order bigint primary key,
PENDING_DAYS int,
SERVICE_TYPE varchar(10),
ASC_code int,
INOUTWTY varchar(10)
);
create table T2(
Service_order bigint,
Part_code varchar(50)
);
insert into T1(Service_order, PENDING_DAYS, SERVICE_TYPE, ASC_code, INOUTWTY)
values
(4182864919 , 18,'CI',3440690,'LP'),
(4182868153 , 18,'CI',4285812,'LP'),
(4182929636 , 17,'CI',4276987,'LP'),
(4182953067 , 16,'CI',3440690,'LP'),
(4182954688 , 16,'CI',6195657,'LP'),
(4182955036 , 16,'PS',6195657,'LP');
insert into T2(Service_order, Part_code)
values
(4182864919,'GH82-11218A'),
(4182864919,'GH96-09406A'),
(4182864919,'GH81-13594A'),
(4182864919,'GH02-11552A'),
(4182864919,'GH02-11553A'),
(4182868153,'GH97-17670B'),
(4182929636,'GH97-17260C'),
(4182929636,'GH02-10203A'),
(4182953067,'GH97-17940C'),
(4182954688,'GH82-10555A'),
(4182954688,'GH97-17852A'),
(4182954688,'GH81-13071A'),
(4182955036,'GH97-17940C')
select T1.*, T2.Part_code
from T1
join T2 on T1.Service_order = T2.Service_order
order by T1.Service_order, T2.Part_code;
EDIT
Alternatively you can load original EXCEL data (first table) and them normalize it in SQL.
-- create normalized tables
create table T1(
Service_order bigint primary key,
PENDING_DAYS int,
SERVICE_TYPE varchar(10),
ASC_code int,
INOUTWTY varchar(10)
);
create table T2(
Service_order bigint,
Part_code varchar(50)
);
-- load data from excel.
create table excelData(
Service_order bigint,
PENDING_DAYS int,
SERVICE_TYPE varchar(10),
ASC_code int,
INOUTWTY varchar(10),
Part_code1 varchar(50),
Part_code2 varchar(50),
Part_code3 varchar(50),
Part_code4 varchar(50),
Part_code5 varchar(50)
);
-- Below i use sample data insert instead of load.
insert into excelData(Service_order, PENDING_DAYS, SERVICE_TYPE, ASC_code, INOUTWTY
,Part_code1, Part_code2, Part_code3, Part_code4, Part_code5)
values
(4182864919 , 18,'CI',3440690,'LP','GH82-11218A','GH96-09406A','GH81-13594A','GH02-11552A','GH02-11553A'),
(4182868153 , 18,'CI',4285812,'LP','GH97-17670B','','','',''),
(4182929636 , 17,'CI',4276987,'LP','GH97-17260C','GH02-10203A','','',''),
(4182953067 , 16,'CI',3440690,'LP','GH97-17940C','','','',''),
(4182954688 , 16,'CI',6195657,'LP','GH82-10555A','GH97-17852A','GH81-13071A','',''),
(4182955036 , 16,'PS',6195657,'LP','GH97-17940C','','','','');
-- store loaded data into normalized tables.
insert into T1(Service_order, PENDING_DAYS, SERVICE_TYPE, ASC_code, INOUTWTY)
select Service_order, PENDING_DAYS, SERVICE_TYPE, ASC_code, INOUTWTY
from excelData;
insert into T2(Service_order, Part_code)
select Service_order, Part_code
from excelData
cross apply (
--unpivot
select Part_code1 as Part_code where len(Part_code1) > 0
union all
select Part_code2 where len(Part_code2) > 0
union all
select Part_code3 where len(Part_code3) > 0
union all
select Part_code4 where len(Part_code4) > 0
union all
select Part_code5 where len(Part_code5) > 0
) unp;
-- check it
select * from T1;
select * from T2;

Update table variable

I have a table variable #searchResult:
DECLARE #searchResult TABLE (
[name_template] NVARCHAR(50),
[record_id] INT,
[record_name] NVARCHAR(50)
);
And table [records]:
CREATE TABLE [records] (
[record_id] INT IDENTITY(1, 1) PRIMARY KEY,
[record_name] NVARCHAR(50)
)
#searchResult contains records with [name_template] filled only. I want to update it with latest [record_id] and [record_name] from [records] table that match [name_template].
I've tried folowing SQL query with no success:
UPDATE #searchResult
SET [record_id] = r.[record_id], [record_name] = r.[record_name]
FROM (
SELECT TOP 1
r.[record_id]
, r.[record_name]
FROM [records] AS r
WHERE r.[record_name] LIKE [name_template]
ORDER BY r.[record_id] DESC
) AS r;
Error message:
Invalid column name 'name_template'.
What is correct syntax to update #searchResult with desired values?
You need to do a CROSS APPLY on the tables.
UPDATE #searchResult
SET [record_id] = r.[record_id],
[record_name] = r.[record_name]
FROM #searchResult SR
CROSS APPLY (
SELECT TOP 1 *
FROM [records]
WHERE [record_name] LIKE [name_template] -- Your wish, but do you really need LIKE matching??
ORDER BY [record_id] DESC
) AS r;
Try this:
UPDATE t
SET [record_id] = r.[record_id],
[record_name] = r.[record_name]
FROM #searchResult t
INNER JOIN
(
SELECT MAX([record_id]) As [record_id]
,[record_name]
FROM [records]
GROUP BY [record_name]
) r
ON r.[record_name] LIKE t.[name_template];
Update:
Seems to be working fine from what I've tested:
Create table and table variable:
CREATE TABLE [records] (
[record_id] INT IDENTITY(1, 1) PRIMARY KEY,
[record_name] NVARCHAR(50)
)
DECLARE #searchResult TABLE (
[name_template] NVARCHAR(50),
[record_id] INT,
[record_name] NVARCHAR(50)
);
Populate with sample data:
INSERT INTO [records] ([record_name]) VALUES('a'), ('a'), ('a'), ('b'), ('b')
INSERT INTO #searchResult ([name_template]) VALUES ('a'), ('b')
Update table variable:
UPDATE t
SET [record_id] = r.[record_id],
[record_name] = r.[record_name]
FROM #searchResult t
INNER JOIN
(
SELECT MAX([record_id]) As [record_id]
,[record_name]
FROM [records]
GROUP BY [record_name]
) r
ON r.[record_name] LIKE t.[name_template];
Check results:
SELECT *
FROM records
SELECT *
FROM #searchResult
DROP TABLE records
Results:
records
record_id record_name
----------- -----------
1 a
2 a
3 a
4 b
5 b
#searchResult
name_template record_id record_name
------------- --------- -----------
a 3 a
b 5 b

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:-

"Invalid Column" when using column from table variable

I'm trying to declare a table variable and then join it to a table I created in the database. Every time I try to insert my "NAME" field into my table, I get the error 'Invalid Column Name "NAME"', even though the GNAME field works fine. What am I doing wrong, and how can I join me NAME column?
DECLARE #Names TABLE
(
ID INT,
NAME VARCHAR(100),
GNAME VARCHAR(100)
)
INSERT INTO #Names
(
ID,
NAME,
GNAME
)
SELECT
CName.ID,
Ref.NAME,
Ref.GNAME
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.ID = Ref.ID
IF ( OBJECT_ID('dbo.ReportTable', 'U') IS NOT NULL)
DROP TABLE dbo.ReportTable
CREATE TABLE [dbo].[ReportTable]
(
[ID_NUMBER] [INT],
[NAME] [VARCHAR](150)
[GNAME] [VARCHAR](150)
)
INSERT INTO [dbo].[ReportTable]
(
ID_NUMBER,
NAME,
GNAME
)
SELECT
C.ID_NUMBER,
N.NAME,
N.GNAME
FROM
#Names AS N
INNER JOIN
#CurrentPositions AS C
ON N.ID_NUMBER = C.ID_NUMBER
Try using a Temp table :
CREATE TABLE #Names
(
ID INT,
NAME VARCHAR(100),
GNAME VARCHAR(100)
)
INSERT INTO #Names
(
ID,
NAME,
GNAME
)
SELECT
CName.ID,
Ref.NAME,
Ref.GNAME
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.ID = Ref.ID
IF ( OBJECT_ID('dbo.ReportTable', 'U') IS NOT NULL)
DROP TABLE dbo.ReportTable
CREATE TABLE [dbo].[ReportTable]
(
[ID_NUMBER] [INT],
[NAME] [VARCHAR](150)
[GNAME] [VARCHAR](150)
)
INSERT INTO [dbo].[ReportTable]
(
ID_NUMBER,
NAME,
GNAME
)
SELECT
C.ID_NUMBER,
N.NAME,
N.GNAME
FROM
#Names AS N
INNER JOIN
#CurrentPositions AS C
ON N.ID_NUMBER = C.ID_NUMBER
I've assumed that you will also change the table variable #CurrentPositions to a temp table
Just remember to drop the tables after you use them.
It is quite possible that all you need to do is wrap your field names in square brackets, e.g.
INSERT INTO #Names
(
[ID],
[NAME],
[GNAME]
)
SELECT
CName.[ID],
Ref.[NAME],
Ref.[GNAME]
FROM
#CurrentPositions AS CName
LEFT OUTER JOIN
dbo.NameField AS Ref
ON
CName.[ID] = Ref.[ID]
If that doesn't fix it, please post the schema of your #CurrentPositions and dbo.NameField tables.

INSERT from JOIN inserts null values

The need to insert values from 3 tables into another table called myTable. The required fields in myTable are:
[Id_student] int,
[id_subjects] int
[degrees] float
[st_Name] nvarchar(30)
[Id_Class] int
[Id_Group] int
[Class] nvarchar(15)
[group] nvarchar(15))` ..
I created the stored procedure below. But after viewing the table I found that only the passed parameters were saved! ie #Id_student , #id_subjects , #degrees. Can anyone explain what is wrong with this code?
CREATE storedprocedure mySp_myTable_insert
#Id_student int,
#id_subjects int,
#degrees int
as
DECLARE #st_Name nvarchar(30)
SELECT #st_Name = pst.st_Name FROM dbo.sudents AS pst where pst.id_student=#id_student ;
INSERT [myTable]
(
[Id_student],
[id_subjects],
[degrees],
[st_Name],
[Id_Class],
[Id_Group],
[Class],
[group]
)
(select
#Id_student,
#id_subjects,
#degrees,
#st_Name
,tc.Id_Class
,tg.Id_Group
,tc.Class
,tg.group
from dbo.subjects sbj
inner join tGroup tg
inner join tClass tc
on tc.Id_Class=tg.Id_Class
on sbj.Id_Group =tg.Id_Group
where sbj.id_subjects=#id_subjects)
I think you should drop the parentheses around the SELECT statement and fix the order of the join-on keywords/clauses.
Try this version:
CREATE storedprocedure mySp_myTable_insert
#Id_student int,
#id_subjects int,
#degrees int
as
DECLARE #st_Name nvarchar(30)
SELECT #st_Name = pst.st_Name FROM dbo.sudents AS pst where pst.id_student=#id_student ;
INSERT [myTable]
(
[Id_student],
[id_subjects],
[degrees],
[st_Name],
[Id_Class],
[Id_Group],
[Class],
[group]
)
select
#Id_student,
#id_subjects,
#degrees,
#st_Name
,tc.Id_Class
,tg.Id_Group
,tc.Class
,tg.group
from dbo.subjects sbj
inner join tGroup tg on sbj.Id_Group =tg.Id_Group
inner join tClass tc on tc.Id_Class=tg.Id_Class
where sbj.id_subjects=#id_subjects
GO