get values from master table based on fields in sqlserver - sql

I want to retrieve the values from master table based on transaction table different col value,
My master table will have username,FirstName,lastName.
My transaction table will have Id,CreatedUser,UpdatedUser.
So I want query to get report from sql server ,get FirstName,lastName from master table for createruser and get FirstName,lastName from master table for updateuser.
Ex:
Master Table
User ID First Name Last Name
cer001 Ds CV
cer002 vb av
Transaction Table
id CreatedUser UdatedUser
2323 cer001 cer002
So Report should get the results like
Id CreatedUser UpdatedUSer
2323 Ds,CV Vb,av
it should be performance wise also good. Please help how to get this

You are looking for self join
select
t.Id, m.FirstName +','+m.LastName as CreatedUser,
mm.FirstName +','+mm.LastName as UpdatdUser
from Master m
inner join Transaction t on t.CreatedUser = m.[User ID]
inner join Master mm on mm.[User ID]= t.UpdatedUser

You should try left join from Transaction table to master table.
LEFT to take care of any NULL values
see working demo
Query will be
create table [Master] ([User ID] varchar(10), [First Name] varchar(10), [Last Name] varchar(10));
insert into [Master] values
('cer001','Ds','CV'),('cer002','vb','av')
create table [Transaction] (id int, CreatedUser varchar(10),UpdatedUser varchar(10))
insert into [Transaction] values
(2323, 'cer001','cer002');
select
ID=T.id,
CreatedUser= ISNULL (M1.[First Name],'')+ ','+ISNULL(M1.[Last Name],'' ),
UpdatedUser= ISNULL (M2.[First Name],'')+ ','+ISNULL(M2.[Last Name],'')
from
[Transaction] T
LEFT JOIN
[Master] M1
ON T.CreatedUser =M1.[User ID]
LEFT JOIN
[Master] M2
ON T.UpdatedUser =M2.[User ID]

Maybe you can try using sub query as below
Select
t.id,
(Select TOP 1 Rtrim(m.[First Name])+','+RTRIM(m.[Last Name]) from [Master] m where m.[User ID] = t.CreatedUser) as CreatedUser,
(Select TOP 1 Rtrim(m.[First Name])+','+RTRIM(m.[Last Name]) from [Master] m where m.[User ID] = t.UpdatedUser) as UpdatedUser
from [Transaction] t

Related

How to insert data in multiple rows of temp tables in sql

How I can insert in same row for example I want to insert all these columns data in first row then second and so on. But my query is inserting data when customer name data is complete, status data is inserted after one row of customer number last data.
CREATE TABLE #tblCustomer
(
CustomerNumber NVARCHAR(1000),
Status NVARCHAR (1000),
CustomerType NVARCHAR (1000)
)
INSERT
INTO #tblCustomer (CustomerNumber)
Select c.CustomerNumber
From Customer.Customer c
INSERT
INTO #tblCustomer (Status)
Select ses.Name
From Customer.Customer c
Left Outer Join COM.StatusEngine_EntityStatus sees
On c.Status = sees.EntityStatusId
And sees.EntityId = 'CustomerStatus'
Join COM.StatusEngine_Status ses
On sees.Status = ses.Status
INSERT
INTO #tblCustomer (CustomerType)
select t.Description
From Customer.Customer c
Join Customer.Type t
On c.TypeId = t.pkTypeId
Receiving output:
0001 null null
0002 null null
NULL active null
NULL active null
NULL null individual
NULL null individual
Expected Output:
0001 active individual
0002 active individual
Without knowing more about your tables, you can insert the first records like so...
INSERT INTO #tblCustomer (CustomerNumber)
select c.CustomerNumber from Customer.Customer c
And then update the remaining columns this way...
UPDATE #tblCustomer
set #tblCustomer.Status = c.Status
from Customer.Customer c
left outer join COM.StatusEngine_EntityStatus sees
on c.Status = sees.EntityStatusId and sees.EntityId = 'CustomerStatus'
join COM.StatusEngine_Status ses
on sees.Status = ses.Status
join #tblCustomer temp
on c.CustomerNumber = temp.CustomerNumber
However doing it like this is really inefficient, you should strive to create an insert that updates all columns in one go.
You can do it like this (I have verified the code with the Northwind sample database from Microsoft - I have chosen that one since you can use it for each SQL server version since SQL 2000):
declare #NumberOfItems int = 10;
CREATE TABLE #tblCustomer (
CustomerNumber NVARCHAR(1000)
,Name NVARCHAR (1000)
,CustomerType NVARCHAR (1000))
insert into #tblCustomer
select CustomerNumber, Name, Status from (select top(#NumberOfItems) ROW_NUMBER() OVER(ORDER BY CustomerID) as No, CustomerID as CustomerNumber from Customers) c
left join (select * from (select top(#NumberOfItems) ROW_NUMBER() OVER(ORDER BY ContactName) as No, ContactName as Name from Customers) q2) j1 on c.No=j1.No
left join (select * from (select top(#NumberOfItems) ROW_NUMBER() OVER(ORDER BY ContactTitle) as No, ContactTitle as Status from Customers) q3) j2 on c.No=j2.No
select * from #tblCustomer
drop table #tblCustomer
It will create a column with numbers from 1 to n for each element you want to import and then it joins it together.
The result of this query is:
Note: While this works, it is not the preferred way to do it, because there is no primary key - normally one would look for primary key / foreign key relationships to join the data together. The way you're intending to fill it puts data together which doesn't necessarily belong together (here each column is sorted and then put together by its row number - i.e. it picks values from rows sorted by its extract column and then putting them together again). If you have no primary key because you're importing data from other sources, you can add WHERE clauses to create a better connection between the inner and the outer select statements - you can find a nice article which might help you with such kind of subqueries here.
This is untested, however, I believe this is what you're after:
INSERT INTO #tblCustomer (CustomerNumber, [Status], CustomerType))
SELECT c.CustomerNumber, ses.[Name], t.[Description]
FROM Customer.Customer c
JOIN COM.StatusEngine_EntityStatus sees ON c.Status = sees.EntityStatusId --Changed to JOIN, as it is turned into a implicit INNER join by the next JOIN
AND sees.EntityId = 'CustomerStatus'
JOIN COM.StatusEngine_Status ses ON sees.[Status] = ses.[Status];
Note my comment regarding your LEFT OUTER JOIN, in that I've changed it to an INNER JOIN.
straight forward SQL here:
CREATE TABLE #tblCustomer
(
CustomerNumber NVARCHAR(1000),
Status NVARCHAR (1000),
CustomerType NVARCHAR (1000)
)
INSERT INTO #tblCustomer (CustomerNumber, Status, CustomerType)
SELECT DISTINCT
c.CustomerNumber,
ses.Name,
t.Description
FROM Customer.Customer c
LEFT OUTER JOIN COM.StatusEngine_EntityStatus sees
On c.Status = sees.EntityStatusId
And sees.EntityId = 'CustomerStatus'
LEFT OUTER JOIN COM.StatusEngine_Status ses
On sees.Status = ses.Status
LEFT OUTER JOIN Customer.Type t
On c.TypeId = t.pkTypeId

Sum on columns with the same ID and different columns?

Using Microsoft SQL Server
I need to create a table that takes the User IDs from the temp table. Collects only those User IDs and then adds all of the Points for that individual user together.
Temp table which pulled all the most recent records for each User ID.
User ID | Points | Date Field
-----------------------------
1 1 10/31/2016
3 1 08/26/2016
Main
User ID | Points | Date Field | Other Field
--------------------------------------------
1 1 10/31/2016 N/A
1 2 10/25/2016 N/A
1 3 09/18/2016 N/A
2 1 08/17/2017 N/A
2 16 07/11/2017 N/A
3 1 08/27/2016 N/A
3 5 05/14/2016 N/A
So take temp table and match those User IDs to the main table. From that data you should only have collected those which match the record IDs in the temp table. From there the report will then be broken down to look like below. Which shows the most recent date, and a sum of all the points for that User ID.
User ID | Points | Date Field | Other Field
---------------------------------------------
1 6 10/31/2016 N/A
3 6 08/27/2016 N/A
I tried this SQL:
SELECT
a.[User ID], a.[Points], a.[Date Field], a.[Other Field1], a.[Other Field2], a.[Other Field3],
(CASE WHEN b.[User ID] = a.[User ID] THEN SUM(a.Points) END) AS [Total Points]
FROM
Main_Table a
INNER JOIN
#Temp b ON b.[User ID] = a.[User ID]
GROUP BY
a.[User ID], [Points], [Date Field], [Other Field1], [Other Field2], [Other Field3]
I get the total points column, but is not adding all the fields with identical User IDs together.
I just need to know where I am going wrong. I'm not the best with SQL and I'm still learning. Please understand I am trying my best to figure this out.
Thank you!
I imagine something like this is what you're looking for:
SELECT
b.[User ID]
, b.[Points]
, b.[Date Field]
, SUM(a.Points) [Total Points]
FROM
#Temp b
INNER JOIN Main_Table a ON b.[User ID] = a.[User ID]
GROUP BY
b.[User ID]
, b.[Points]
, b.[Date Field]
But then the question would be, which of the other fields from Main_Table do you want to keep?
I imagine possibly something like this:
SELECT
b.[User ID]
, b.[Points]
, b.[Date Field]
, m.[Other_Field] -- etc.
, SUM(a.Points) [Total Points]
FROM
#Temp b
INNER JOIN Main_Table m ON
b.[User ID] = m.[User ID]
AND b.[Date Field] = m.[Date Field]
INNER JOIN Main_Table a ON b.[User ID] = a.[User ID]
GROUP BY
b.[User ID]
, b.[Points]
, b.[Date Field]
, m.[Other_Field]
To get Sum, you have to group by fields that are non-changing. So User ID is the non-changing field you would want to SUM by. The group by is done to this non-aggregate field User ID. The problem with date and [Other Field] is that they are changing often. This defeats the group by. You have to query back to the original table to get the max date field if that's your intent. I'm not sure what [Other Field] are, but you have to take into account if they are different changing values.
SELECT dT.[User ID]
,dT.Points
,(SELECT MAX([Date Field])
FROM #main M2
WHERE M2.[User ID] = dT.[User ID]) AS [Date Field]
FROM (
SELECT M.[User ID]
,SUM(M.Points) AS Points
FROM #main M
WHERE [User ID] IN (SELECT [User ID] FROM #temp)
GROUP BY M.[User ID]
) AS dT
Creates output:
User ID Points Date Field
1 6 2016-10-31
3 6 2016-08-27
I assume this should help
--======================= CREATE TEMP TABLE==============================
CREATE TABLE #TEMP ([USER ID] INT,
POINTS INT,
[DATE FIELD] DATE)
--======================= VALUES ON THE TABLE ===============================
INSERT INTO #TEMP VALUES ( 1 ,1,'10-31-2016')
INSERT INTO #TEMP VALUES (3,1,'08-26-2016')
--======================== CREATE MAIN TABLE ============================
CREATE TABLE #MAIN ([USER ID] INT,
POINTS INT,
[DATE FIELD] DATE,
[OTHER FIELD] NVARCHAR(50))
--======================= VALUES ON MAIN TABLE===================
INSERT INTO #MAIN VALUES ( 1,1,'10-31-2016','N/A')
INSERT INTO #MAIN VALUES ( 1,2,'10-25-2016','N/A')
INSERT INTO #MAIN VALUES ( 1,3,'09-18-2016','N/A')
INSERT INTO #MAIN VALUES ( 2,1,'08-17-2017','N/A')
INSERT INTO #MAIN VALUES ( 2,16,'07-11-2017','N/A')
INSERT INTO #MAIN VALUES ( 3,1,'08-27-2016','N/A')
INSERT INTO #MAIN VALUES ( 3,5,'05-14-2016','N/A')
--=====GETTING SUM OF YOUR POINTS=====
SELECT T2.[USER ID],
SUM(T1.[POINTS]) AS [TOTAL POINT],
T2.[DATE FIELD],
T1.[OTHER FIELD]
FROM #MAIN AS T1
RIGHT JOIN #TEMP AS T2
ON T1.[USER ID] = T2.[USER ID]
GROUP BY T2.[USER ID],
T2.[DATE FIELD],
T1.[OTHER FIELD]
DROP TABLE #TEMP
DROP TABLE #MAIN

SQL Loop/Crawler

I am trying to figure out some ways to accomplish this script. I import an excel sheet and then I need to populate 5 different tables based on this excel sheet. However for this example I just need help with the initial loop then I think I can work through the rest.
select distinct Department from IPACS_New_MasterList
where Department is not null
This provides me a list of 7 different departments.
Dep1, Dep2, Dep3, Dep4, Dep5, Dep6, Dep7
For each of these departments I need to perform some code.
Step #1:
Insert the department into table_one
I then need to keep the SCOPE_IDENTITY() for the rest of the code.
Step #2
perform the second loop (inserting all functions in that department into table2.
I'm not sure how to really do a foreach row in this select statement loop, or if I need to do something completely different. I've looked at several answers but can't seem to find exactly what I'm looking for.
Sample Data:
Source Table
Dep1, func1, process1, procedure1
dep1, func1, process1, procedure2
dep1, func1, process2, procedure3
dep1, func1, process2, procedure4
dep1, func1, process2, procedure5
dep1, func2, process3, procedure6
dep2, func3, process4, procedure7
My Tables:
My first table is a list of every department from the above query. With a key on the departmentID. Each department can have many functions.
My second table is a list of all functions with a key on functionID and a foreign key on departmentID. Each function must have 1 department and can have many processes
My third table is a list of all processes with a key on processID and a foreign key on functionID. Each process must have 1 function and can have many procedures.
There are two approaches you can use without a loop.
1) If you have candidate keys in your source (department name) just join your source table back to the table you inserted
e.g.
INSERT INTO Department
(Name)
SELECT DISTINCT Dep1
FROM SOURCE;
INSERT INTO Functions
(
Name,
DepartmentID)
SELECT DISTINCT
s.Func1,
d.DepartmentID
FROM
source s
INNER JOIN Department d
on s.dep1 = d.name;
INSERT INTO
processes
(
name,
FunctionID,
[Procedure]
)
SELECT
s.process1,
f.FunctionID,
s.procedure1
FROM
source s
INNER JOIN Department d
on s.dep1 = d.name
INNER JOIN Functions f
on d.DepartmentID = f.departmentID
and s.func1 = f.name;
SQL Fiddle
2) If you don't have candidate keys in your source then you can use the output clause
For example here if a department weren't guaranteed to be unique this would correctly find only the newly add
DECLARE #Department TABLE
(
DepartmentID INT
)
DECLARE #Functions TABLE
(
FunctionID INT
)
INSERT INTO Department
(Name)
OUTPUT INSERTED.DepartmentID INTO #Department
SELECT DISTINCT Dep1
FROM SOURCE
INSERT INTO Functions
(
Name,
DepartmentID)
OUTPUT INSERTED.FunctionID INTO #FunctionID
SELECT DISTINCT
s.Func1,
d.DepartmentID
FROM
source s
INNER JOIN Department d
on s.dep1 = d.name
INNER JOIN #Department d2
ON d.departmentID = d2.departmentID;
INSERT INTO
processes
(
name,
FunctionID,
[Procedure]
)
SELECT
s.process1,
f.FunctionID,
s.procedure1
FROM
source s
INNER JOIN Department d
on s.dep1 = d.name
INNER JOIN Functions f
on d.DepartmentID = f.departmentID
and s.func1 = f.name
INNER JOIN #Functions f2
ON f.Functions = f2.Functions
SELECT * FROM Department;
SELECT * FROm Functions;
SELECT * FROM processes;
SQL Fiddle
If I am understanding what you are trying to do... yes you can use a loop. Its not really talked about and I bet I am going to get some feedback from other SQL developers that its not a best practice. But if you really need to do a loop
DECLARE #rowcount as int
DECLARE #numberOfRows as int
SET #rowcount = 0
SET #numberOfRows = SELECT COUNT(*) from tablename --put in anything to get the number of times to loop.
WHILE #numberOfRows <= #rowcount
BEGIN
--Put whatever process you need to repeat here
SET #rowcount = #rowcount + 1
END
Assuming you have tables set up with an IDENTITY field set for the Primary Key, you can populate each successive table's foreign key by joining to the previous table and the source table, something like:
INSERT INTO Table1
SELECT DISTINCT Department
FROM SourceTable
GO
INSERT INTO Table2
SELECT DISTINCT b.Deptartment_ID, a.Function
FROM SourceTable a
JOIN Table1 b
ON a.Department = b.Department
GO
INSERT INTO Table3
SELECT DISTINCT b.Function_ID, a.Process
FROM SourceTable a
JOIN Table2 b
ON a.Function = b.Function
GO
INSERT INTO Table4
SELECT DISTINCT b.Process_ID, a.Procedure
FROM SourceTable a
JOIN Table3 b
ON a.Process = b.Process
GO

SQL Server: select has too many columns for insert

I'm trying to run this query and I keep getting this error:
The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns.
This error comes after I try doing INSERT INTO #tempTable SELECT.... It worked just fine when I had only 2 columns for each temp table, but now that I've added a third, it keeps giving me this error even though it appears to be selecting 3 columns to insert into the table with 3 columns.
The query overall is trying to get a few column values, (customer ids, contacts, and a salesman id) over different tables, but the problems have come from needing to root out duplicate customer IDs and making sure that only 1 salesman and 1 contact showing up for each customer. If it wasn't for the salemen id, the query would work perfectly. Here is what I have so far:
if object_id('tempdb..#tempTable') IS NOT NULL DROP TABLE #tempTable
if object_id('tempdb..#tempTable2') IS NOT NULL DROP TABLE #tempTable2
CREATE TABLE #tempTable(
CustomerID int,
ContactName nvarchar(50),
SalesmenID nvarchar(4)
)
CREATE TABLE #tempTable2(
CustomerID int,
ContactName nvarchar(50),
SalesmenID nvarchar(4)
)
INSERT INTO #tempTable
(CustomerID, ContactName,SalesmenID)
SELECT Customers.[Customer ID],Salesmen.[4 Letter ID],
CASE([Customer Contact].defaultprintonorder)
WHEN 0
THEN 'zzzzzzz_NOCONTACT'
ELSE
[Customer Contact].[Contact Name]
END as ContactName
From Customers
LEFT JOIN [Customer Contact] on Customers.[Customer ID]=[Customer Contact].[Customer ID]
Left Join [Customer Salesmen] On Customers.[Customer ID]=[Customer Salesmen].[Customer ID]
INNER JOIN Salesmen on [Customer Salesmen].[Salesman Name]=Salesmen.[Salesman Name]
WHERE Customers.[Customer ID] NOT IN(SELECT CustomerID FROM #tempTable)
GROUP BY Customers.[Customer ID], [Contact Name], DefaultPrintOnOrder
INSERT INTO #tempTable2 (CustomerID, ContactName,SalesmenID)
SELECT distinct CustomerID, '', SalesmenID FROM #tempTable
UPDATE #TempTable2 SET
#tempTable2.CustomerID=#tempTable.CustomerID,
#tempTable2.ContactName=#tempTable.ContactName
FROM
#TempTable2
INNER JOIN #TempTable ON #TempTable2.CustomerID=#TempTable.CustomerID
SELECT Salesmen.[4 Letter ID],
[Customers].[Customer ID],
[Customer Contact].[Contact Name]
FROM Customers
Right JOIN #TempTable2 ON
Customers.[Customer ID]=#TempTable2.CustomerID
Right JOIN [Customer Salesmen] ON
#TempTable2.CustomerID=[Customer Salesmen].[Customer ID]
INNER JOIN
[Salesmen] ON
[Customer Salesmen].[Salesman Name]=Salesmen.[Salesman Name]
LEFT JOIN
[Customer Contact] ON
#TempTable2.[CustomerID]=[Customer Contact].[Customer ID]
EDIT:
I added SalesmenID to the inserts, but now I'm getting this error message 3 times:
Invalid column name 'SalesmenID'.
It comes up once for the temptable insert and twice for the temptable2 insert
You're trying to store 3 values (Customers.[Customer ID], Salesmen.[4 Letter ID], ContactName) in 2 fields (CustomerID, ContactName)
INSERT INTO #tempTable
(CustomerID, ContactName)
SELECT Customers.[Customer ID],Salesmen.[4 Letter ID],
CASE([Customer Contact].defaultprintonorder)
WHEN 0
THEN 'zzzzzzz_NOCONTACT'
ELSE
[Customer Contact].[Contact Name]
END as ContactName
Are you sure the problem is where you indicated?
This insert has 2 destination columns and 3 select columns:
INSERT INTO #tempTable
(CustomerID, ContactName) -- 2 columns
SELECT Customers.[Customer ID], --column 1
Salesmen.[4 Letter ID], --column 2
CASE([Customer Contact].defaultprintonorder) -- column 3!
WHEN 0
THEN 'zzzzzzz_NOCONTACT'
ELSE
[Customer Contact].[Contact Name]
END as ContactName
From Customers...

Writing a complex trigger

I am using SQL Server 2000. I am writing a trigger that is executed when a field Applicant.AppStatusRowID
Table Applicant is linked to table Location, table Company & table AppStatus.
My issue is creating the joins in my query.
When Applicant.AppStatusRowID is updated, I want to get the values from
Applicant.AppStatusRowID, Applicant.FirstName, Applicant.Lastname, Location.LocNumber, Location.LocationName, Company.CompanyCode, AppStatus.DisplayText
The joins would be :
Select * from Applicant A
Inner Join AppStatus ast on ast.RowID = a.AppStatusRowID
Inner Join Location l on l.RowID = a.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
This is to be inserted into an Audit table (fields are ApplicantID, LastName, FirstName, Date, Time, Company, Location Number, Location Name, StatusDisposition, User)
My issue is the query for the inner join...
First lets introduce you to the inserted and deleted pseudotables which are available only in triggers. Inserted has new values and delted has old values or records being deleted.
You do not want to insert all records into your audit table only those in inserted.
So to insert into an audit table you might want something like inside the trigger code:
insert Myaudittable (<insert field list here>)
Select <insert field list here> from Inserted i
Inner Join AppStatus ast on ast.RowID = i.AppStatusRowID
Inner Join Location l on l.RowID = i.LocationRowID
Inner Join Company c on c.RowID = l.CompanyRowID
I would personally add columns for old and new values, a column for the type of change and what the date of the change and what user made the change, but you I'm sure have your own requirement to follow.
Suggest you read about triggers in Books online as they can be tricky to get right.
Here's one way to test and debug trigger that I often use. First I create temp tables names #delted and #inserted that have the sturcture of the table I'm going to put the trigger on. Then I write the code to use those instead of the deleted or inserted tables. That wa y I can look at things as I go and make sure everything is right before I change the code to a trigger. Example below with you code added in and modified slightly:
Create table #inserted(Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #inserted
select 1, 'Jones', 'Ed', 30
union all
select 2, 'Smith', 'Betty', 20
Create table #deleted (Rowid int, lastname varchar(100), firstname varchar(100), appstatusRowid int)
Insert #deleted
select 1, 'Jones', 'Ed', 10
union all
select 2, 'Smith', 'Betty', 20
--CREATE TRIGGER tri_UpdateAppDisp ON dbo.Test_App
--For Update
--AS
--If Update(appstatusrowid)
IF exists (select i.appstatusRowid from #inserted i join #deleted d on i.rowid = d.rowid
Where d.appstatusrowid <> i.appstatusrowid)
BEGIN
--Insert AppDisp(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDisp,[Username])
Select d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,
l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User
From #deleted d
Join #inserted i on i.rowid = d.rowid
--From deleted d
--Join inserted i on i.rowid = d.rowid
Inner join Test_App a with (nolock) on a.RowID = d.rowid
inner join location l with (nolock) on l.rowid = d.Locationrowid
inner join appstatus ast with (nolock) on ast.rowid = d.appstatusrowid
inner join company c with (nolock) on c.rowid = l.CompanyRowid
Where d.appstatusrowid <> i.appstatusrowid)
end
Once you get the data for the select correct, then it is easy to uncomment out the trigger code and the insert line and change #deleted or #inserted to deleted or inserted.
You'll note I had two records in the temp tables, one of which met your condition and one of which did not. This allows you to test mulitple record updates as well as results that meet the condition and ones that don't. All triggers should be written to handle multiple records as they are not fired row-by-row but by batch.