Sum on columns with the same ID and different columns? - sql

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

Related

Update Record and Insert Data from One Table Via Join

I have a table (Table 1) which is a list of employees and data points about them. The data that populated Table 1 is regularly changed and added to in its source system and then is loaded into another table (Table 2) via a CSV.
If data changes for a certain employee, I want to update that employees record in Table 1 and then append that changed employee to Table 1 along with any new employees from Table 2 that didn't already exist in Table 1.
Example:
Table1:
Status | ID | Name | Department | Title
Active 767 John Tech Analyst
Active 789 Alex Tech Courier
Table2:
Status | ID | Name | Department | Title
Active 767 John Tech Director -- the title changed for this employee
Active 789 Alex Tech Courier
Desired Output of Table1:
Status | ID | Name | Department | Title
Active 767 John Tech Director
Changed 767 John Tech Analyst
Active 789 Alex Tech Courier
With the query below, I am attempting to insert this data via an outer join however I am producing duplicates of each row, when I only want to add employees who have changed their department, title, etc. and any new employees that don't already exist in Table1
How can I insert this data without duplicating all the roles.
Query:
UPDATE [DATABASE].[dbo].[CBC_legacy]
SET [Position Status] = 'Changed'
FROM [DATABASE].[dbo].[CBC_data] CBC
WHERE (CBC.[Employee ID] = [CBC_legacy].[employee ID] AND (CBC.[Job Title] <> [CBC_legacy].[Job Title] OR CBC.[Home Department] <> [CBC_legacy].[Home Department] OR CBC.[Annual Salary] <> [CBC_legacy].[Annual Salary]))
INSERT INTO [DATABASE].[dbo].[CBC_legacy] (
[Position Status]
,[Employee ID]
,[Full Legal Name]
,[Annual Salary]
,[Job Title]
,[Home Department]
SELECT
[CBC].[Position Status]
,[CBC].[Employee ID]
,[CBC].[Full Legal Name]
,[CBC].[Annual Salary]
,[CBC].[Job Title]
,[CBC].[Home Department]
FROM [DATABASE].[dbo].[CBC_data] AS CBC
FULL JOIN [DATABASE].[dbo].[CBC_legacy] AS CBCL
ON [CBC].[Employee ID] = [CBCL].[Employee ID]
AND [CBC].[Job Title] = [CBCL].[Job Title]
AND [CBC].[Home Department] = [CBCL].[Home Department]
AND [CBC].[Annual Salary] = [CBCL].[Annual Salary]
ORDER BY [Full Legal Name]
SELECT * FROM [DATABASE].[dbo].[CBC_legacy] ORDER BY [Full Legal Name]

get values from master table based on fields in sqlserver

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

SQL Query , Clients with No Client Contact and No Active Client Contact

I need a query to get the Name of the Clients where there is no Client Contact record and if there is any Client Contact then they are ended. Please see below table structure.
Table : Client
Client ID Client Name
-------------------------
1 John
2 Sean
3 Johnson
Table : Client_Contact
Client Contact ID Client ID Start Date End Date
---------------------------------------------------------
1 1 1/1/1999 2/2/1999
2 1 1/2/1999 2/3/1999
3 1 1/3/1999 2/4/1999
4 2 1/2/2005 1/2/2007
5 2 1/3/2005 NULL
The query will return Johnson and Sean.
Johnson has no Client Contact , so it is coming up in the Query
John has Client Contact but all the Client Contact are ended , so it is coming up in the query
Sean has Client Contact but one of the record is not ended , so it is not coming up in the query.
Thanks in advance for the query.
Here's a query pattern that I use for queries like this that can give substantial performance gains compared to "left join" patterns, when the tables involved get really large:
select c.[Client Name]
from Client c
where not exists
(
select *
from Client_Contact cc
where c.[Client ID] = cc.[Client ID]
and cc.[End Date] is null
)
Try ..
select distinct cl.*
from Client cl
left outer join Client_Contact clcnt
on cl.[Client ID] = clcnt.[Client ID]
where (clcnt.[Client ID] IS NULL OR clcnt.[End Date] IS NULL)
I hope this query might work for you
select c.* from client c
left join (select max([Client Contact ID]) ClientContactID,[Client ID] from client_contact
group by [client id]) ce on c.[Client ID]=ce.[Client ID]
left join client_contact ce1 on ce.[Client Contact ID]=ce1.[Client Contact ID]
where ce.[Client ID] is null
or ce1.[End Date] is not null

Update existing records table with ID of foreign key table

I have the following tables:
and
I recently added the [History Table ID] column and added a Foreign Key Reference to the History table. What has to happen is, the Value of the [History Table ID] column has to be updated with the ID value of the History table. I have already been able to get it right with 2 entries, the entries that have the ID of Diary table in the Description column of the History table. This query below accomplishes that:
Update Diary
SET [History Table ID] = History.ID
from History with (nolock)
WHERE [Lookup Table HA] = 7
and [Lookup Table HAS] = 19
and Description LIKE 'Diary item (%'
and PATINDEX('%)%', Description) > 13
and Dairy.ID = SUBSTRING(Description, 13, PATINDEX('%)%', Description)-13)
Is there any way that the rest can be updated at all? I just can't get my head around this.
Thanks in advance.
UPDATE:
Please see below for Updated Table shots: This is where my problem in Updating and joining lies:
As you have mentioned in comment, "IssueNumber will always be the same. GlobalId will also always be the same in both tables." So this will work fine:
UPDATE Diary
SET [History Table ID] = History.ID
FROM History WITH (NOLOCK)
WHERE Diary.[Global ID] = History.[Global ID]
AND Diary.IssueNumber = History.IssueNumber
Perhaps this isn't correct, but it looks like the Global Id (and Issue number) connects the two tables. If so, you can do:
Update Diary
SET [History Table ID] = History.ID
from History with (nolock)
WHERE Diary.[Global ID] = History.[Global ID] and
Diary.[Issue number] = History.[Issue number];
Otherwise, you need to figure out the logic that connects one record in History to a record in the Diary table.
EDIT:
Let me assume you want the biggest history id when there are multiple matches:
Update Diary
SET [History Table ID] = h.ID
from (select [Global ID], [Issue number], max(id) as maxid
from History with (nolock)
group by [Global ID], [Issue number]
) h
WHERE Diary.[Global ID] = h.[Global ID] and
Diary.[Issue number] = h.[Issue number];

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