Update table based on two other tables - sql

I have 3 tables Customer, customerCategory, Attendance as shown below:
Customer:
CustomerId | CustomerCategory | Name
A1 | 2 | User1
B1 | 1 | User2
C1 | 3 | User3
CustomerCategory
CustCategoryId | CategoryName | StartTime | EndTime
1 | Category1 | 8:15 | 17:15
2 | Category2 | 7.30 | 17:30
3 | Category3 | 8.15 | 15:15
Attendance
Id | CustomerId | InTime | OutTime
1 | A1 | 7:30 | 17:30
2 | A1 | 7:30 | NULL
3 | B1 | 8.15 | NULL
4 | C1 | 8:10 | NULL
I want to update Attendance Table Outtime column to the relevant Endtime from CustomerCategory table where Attendane.Outime is NULL. I was hoping I could write a merge query but I am confused. Is there any other way I can update Attenance table to set relevant OutTime?

UPDATE Attendance
SET Attendance.OutTime = CustomerCategory.EndTime
FROM Attendance
INNER JOIN Customer
ON (Attendance.CustomerID = Customer.CustomerID)
INNER JOIN CustomerCategory
ON (Customer.CustomerCategory = CustomerCategory.CustCategoryId)
WHERE Attendance.OutTime IS NULL;
You might need to play with syntax a little bit, since I haven't been dealing with MS SQL for a while, but the basic idea is as above. Please let me know if you will have any difficulties.

Try the following using Merge:
Declare #Customer table (CustomerId varchar(5), CustomerCategory int, Name varchar(10))
insert into #CUSTOMER
select 'A1', 2, 'User1' union
select 'B1', 1, 'User2' union
select 'C1', 3, 'User3'
Declare #CustomerCategory TABLE (CustCategoryId INT, CategoryName varchar(10), StartTime time, EndTime time)
insert into #CustomerCategory
select 1, 'Category1', '8:15', '17:15' union
select 2, 'Category2', '7:30', '17:30' union
select 3, 'Category3', '8:15', '15:15'
Declare #Attendance table (Id int, CustomerId varchar(5), InTime time, OutTime time)
insert into #Attendance
select 1, 'A1', '7:30', '17:30' union
select 2, 'A1', '7:30', NULL union
select 3, 'B1', '8:15', NULL union
select 4, 'C1', '7:30', NULL
select * from #Customer
select * from #CustomerCategory
select * from #Attendance
merge #Attendance a
using
(select c.CustomerId, cc.EndTime from #Customer c
join #CustomerCategory cc on c.CustomerCategory = cc.CustCategoryId)x
on x.CustomerId = a.CustomerId
and a.OutTime is null
when matched then update
set a.OutTime = x.EndTime ;
select * from #Attendance
HTH!

Related

Adding new data in columns, from another table - SQL ORACLE

I have a table with some records
MASTER TABLE
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 2 | 2014-01-06 | 30 |
x------x--------------------x-------x
I have another table with parameters of this record (ID)
TABLE2
x------x--------------------x------------x
| Id | Parameter | Value |
x------x--------------------x------------x
| 1 | Humidty | 10 |
| 1 | Temperature | 30 |
| 2 | Humidty | 50 |
| 2 | Temperature | 40 |
x------x--------------------x------------x
As result I want this: (combine based on ID)
Result table
x------x--------------------x-------------------------x
| Id | Period | Humidty | Temperature |
x------x--------------------x-------------------------x
| 1 | 2014-01-13 | 10 | 30 |
| 2 | 2014-01-06 | 50 | 40 |
x------x--------------------x-------------------------x
How Can I do something like that? Inner join will not work I think.
Join the tables and use conditional aggregation with case to extract the 2 columns:
select t1.id, t1.period,
max(case when t2.parameter = 'Humidty' then t2.value end) Humidty,
max(case when t2.parameter = 'Temperature' then t2.value end) Temperature
from mastertable t1 inner join table2 t2
on t2.id = t1.id
group by t1.id, t1.period
You can pivot:
SELECT * FROM
(
SELECT
t_m.Id
, t_m.Period
, t_2.Parameter
, t_2.Value
FROM #tbl_Master t_m
INNER JOIN #tbl_2 t_2 ON t_2.Id = t_m.Id
)AS t
PIVOT
(
MAX(t.Value)
FOR t.Parameter IN ([Humidity], [Temperature])
)pvt
and sample data:
DECLARE #tbl_Master TABLE
(
Id int,
Period Date,
QTY int
)
DECLARE #tbl_2 TABLE
(
Id int,
Parameter varchar(30),
[Value] int
)
INSERT INTO #tbl_Master
(
Id,
Period,
QTY
)
VALUES
(1, '2014-01-13', 10)
, (2, '2014-01-06', 30)
INSERT INTO #tbl_2
(
Id ,
Parameter ,
[Value]
)
VALUES
( 1, 'Humidity', 10)
, ( 1, 'Temperature' , 30)
, ( 2, 'Humidity', 50)
, ( 2, 'Temperature' , 40)
OUTPUT:
Id Period Humidity Temperature
1 2014-01-13 10 30
2 2014-01-06 50 40
Try this
DECLARE #Mastertable AS TABLE(Id INT,PERIOD DATE,QTY INT)
INSERT INTO #Mastertable
SELECT 1 ,'2014-01-13', 10 UNION ALL
SELECT 2 ,'2014-01-06', 30
DECLARE #Childtable AS TABLE(Id INT,Parameter VARCHAR(100), Value INT)
INSERT INTO #Childtable
SELECT 1 ,'Humidty' , 10 UNION ALL
SELECT 1 ,'Temperature' , 30 UNION ALL
SELECT 2 ,'Humidty' , 50 UNION ALL
SELECT 2 , 'Temperature' , 40
SELECT Id,Period,[Humidty],[Temperature]
FROM
(
SELECT c.Id,
m.PERIOD,
Parameter,
c.Value
FROM #Mastertable m
INNER JOIN #Childtable c
ON m.Id = c.Id
) AS srC
pivot
(MAX(Value) FOR Parameter IN ([Humidty],[Temperature])
) AS PVT
Result
Id Period Humidty Temperature
----------------------------------
1 2014-01-13 10 30
2 2014-01-06 50 40

Combining select and select union in SQL Server

I have 2 tables
Table A with 3 columns : ID, NAME, VALUE 1
Table B with 3 columns : ID, NAME, VALUE 2
Table A :
ID : A1, A2
NAME: AAA, BBB
VALUE 1 : 1000,2000
Table B :
ID : B1, B2
NAME: CCC,DDD
VALUE 1 : 3000,4000
And I want to show the result like this :
ID, NAME, VALUE 1, VALUE 2
A1 AAA 1000
A2 BBB 2000
A3 CCC 3000
A4 DDD 4000
I have tried union and it works for id, name column. What about regular select + union select, is it possible ?
You can use union all:
select id, name, value1, null as value2
from a
union all
select id, name, null as value1, value2
from b;
online demonstration
MS SQL Server 2017 Schema Setup:
CREATE TABLE Table1
([ID] varchar(2), [NAME] varchar(3), [VALUE1] int)
;
INSERT INTO Table1
([ID], [NAME], [VALUE1])
VALUES
('A1', 'AAA', 1000),
('A2', 'BBB', 2000)
;
CREATE TABLE Table2
([ID] varchar(2), [NAME] varchar(3), [VALUE2] int)
;
INSERT INTO Table2
([ID], [NAME], [VALUE2])
VALUES
('B1', 'CCC', 3000),
('B2', 'DDD', 4000)
;
Query 1:
select id, name, value1, null as value2
from table1
union all
select id, name, null as value1, value2
from table2
Results:
| id | name | value1 | value2 |
|----|------|--------|--------|
| A1 | AAA | 1000 | (null) |
| A2 | BBB | 2000 | (null) |
| B1 | CCC | (null) | 3000 |
| B2 | DDD | (null) | 4000 |
You can also use Full Outer Join
SELECT a.id, a.name, a.value1, b.value2
FROM tableA as a
FULL OUTER JOIN tableB AS b ON
a.id = b.id

SQL Query group by in case statement

I Have three tables like bellow
**tRole**
+--------+----------+-----------+
| RoleID | RoleCode | RoleTitle |
+--------+----------+-----------+
| 1 | Role1 | RT1 |
| 2 | Role2 | RT2 |
| 3 | Role3 | RT3 |
+--------+----------+-----------+
**tEmployee**
+-------+-------+
| EmpID | Name |
+-------+-------+
| 1 | Emp 1 |
| 2 | Emp 2 |
| 3 | Emp 3 |
+-------+-------+
**tEmployeeRole**
+-------+--------+
| EmpID | RoleID |
+-------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
+-------+--------+
I want a output like below ,If a role mapped with only one employee then employee name will show other wise Multiple will show.
+--------+----------+-----------+----------+
| RoleID | RoleCode | RoleTitle | Employee |
+--------+----------+-----------+----------+
| 1 | Role1 | RT1 | Multiple |
| 2 | Role2 | RT2 | Multiple |
| 3 | Role3 | RT3 | Emp 3 |
+--------+----------+-----------+----------+
I write bellow query but when I group by emp.First_Name then the result is wrong
select cr.RoleCode,cr.RoleID,
case
when count(ear.RoleID)=1 then emp.First_Name
else 'M' end as 'AssignedTO'
from tRole as cr
left outer join tEmployeeRole as ear on cr.RoleID=ear.RoleID
left outer join tEmployee as emp on ear.EmployeeID=emp.EmployeeID
group by cr.RoleCode,crRoleID,emp.First_Name
Hello You can use this query for your solution :
you need to count with partition and use distinct data
DECLARE #tRole TABLE (
RoleID INT
,RoleCode VARCHAR(50)
,RoleTitle VARCHAR(50)
)
DECLARE #tEmployee TABLE (
EmpID INT
,EmpName VARCHAR(50)
)
DECLARE #tEmployeeRole TABLE ( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
SELECT DISTINCT tRole.RoleID
, RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID
You can Modify the answer from #Pratik to add a col that lists the employees
;with CTE as(
SELECT
DISTINCT tRole.RoleID
RoleCode
, RoleTitle
, CASE WHEN COUNT(tEmployeeRole.EmpID) OVER ( PARTITION BY tEmployee.EmpID ) = 1 THEN tEmployee.EmpName ELSE 'Multiple'END [Employee]
FROM #tEmployee tEmployee
LEFT OUTER JOIN #tEmployeeRole tEmployeeRole ON tEmployeeRole.EmpID = tEmployee.EmpID
LEFT OUTER JOIN #tRole tRole ON tRole.RoleID = tEmployeeRole.RoleID
)
select *
,stuff( (select ','+EmpName from #tEmployee IE inner join #tEmployeeRole IER on IE.EmpID = IER.EmpID where IER.RoleID = CTE.rolecode for xml PATH('') ),1,1,'') AS EMList
from CTE
This query might help you out . Make a try
Your Tables Data looks like
create TABLE #tRole (RoleID INT ,RoleCode VARCHAR(50) ,RoleTitle VARCHAR(50) )
create TABLE #tEmployee (EmpID INT ,EmpName VARCHAR(50) )
create TABLE #tEmployeeRole( EmpID INT, RoleID INT )
INSERT #tRole ( RoleID, RoleCode, RoleTitle )
SELECT 1, 'Role1', 'RT1'
UNION
SELECT 2, 'Role2', 'RT2'
UNION
SELECT 3, 'Role3', 'RT3'
INSERT #tEmployee ( EmpID, EmpName )
SELECT 1, 'Epm 1'
UNION
SELECT 2, 'Epm 2'
UNION
SELECT 3, 'Epm 3'
INSERT #tEmployeeRole ( EmpID, RoleID )
SELECT 1, 1
UNION
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 2, 2
UNION
SELECT 3, 3
Desired Query
;with cte as
(
select tr.roleid,tr.rolecode,tr.roletitle,te.empname
,COUNT(ter.EmpID) OVER ( PARTITION BY ter.EmpID ) as emp_count
from #tEmployee te
inner join #tEmployeeRole tER on tER.empid=te.empid
inner join #tRole tr on tr.roleid=ter.roleid
)
select distinct RoleID,RoleCode,RoleTitle
,case when emp_count>1 then 'Multiple' else empname end as Employee
from cte

SQL Server: Select all records from a table when values from three columns are in the columns of a previous query's result

I have a table with columns:
ID Date Code Amt Type
1 6/1/17 56 100.0 A
2 6/3/17 57 200.0 B
3 6/5/17 58 300.0 C
4 6/7/17 59 400.0 D
Based on a previous query ran, I received this result:
ID Date Code
1 6/1/17 56
2 6/3/17 57
I need to run a select query that grabs all the records from the first column based on the results from the query above, as in some kind of select that would only return:
ID Date Code Amt Type
1 6/1/17 56 100.0 A
2 6/3/17 57 200.0 B
Assuming you have a table TblYours
you could write a query like below
select * from
TblYours T join
(
select ID, Date, Code from #yourQuery -- replace the inner query with your query
) T2
ON T.ID=T2.ID
AND T.Date=T2.Date
AND T.Code= T2.Code
You can do it with a CTE like:
DECLARE #T TABLE (ID INT, Date DATE, Code INT, Amt DECIMAL(4,1), Type CHAR(1));
INSERT INTO #T VALUES
(1, '2017-01-06', 56, 100, 'A'),
(2, '2017-03-06', 57, 200, 'B'),
(3, '2017-05-06', 58, 300, 'C'),
(4, '2017-07-06', 59, 400, 'D');
WITH CTE AS(
SELECT ID, DATE, CODE /* I don't know how your query looks like*/
FROM #T
WHERE ID IN (1,2)
)
SELECT *
FROM #T
WHERE ID IN (SELECT ID FROM CTE);
Result:
+----+---------------------+------+-------+------+
| ID | Date | Code | Amt | Type |
+----+---------------------+------+-------+------+
| 1 | 06.01.2017 00:00:00 | 56 | 100,0 | A |
| 2 | 06.03.2017 00:00:00 | 57 | 200,0 | B |
+----+---------------------+------+-------+------+
Or using a subquery with INNER JOIN like:
DECLARE #T TABLE (ID INT, Date DATE, Code INT, Amt DECIMAL(4,1), Type CHAR(1));
INSERT INTO #T VALUES
(1, '2017-01-06', 56, 100, 'A'),
(2, '2017-03-06', 57, 200, 'B'),
(3, '2017-05-06', 58, 300, 'C'),
(4, '2017-07-06', 59, 400, 'D');
SELECT TT.*
FROM #T TT INNER JOIN
(SELECT ID, DATE, CODE /* I don't know how your query looks like*/
FROM #T
WHERE ID IN (1,2)) T ON TT.ID = T.ID;
Result:
+----+---------------------+------+-------+------+
| ID | Date | Code | Amt | Type |
+----+---------------------+------+-------+------+
| 1 | 06.01.2017 00:00:00 | 56 | 100,0 | A |
| 2 | 06.03.2017 00:00:00 | 57 | 200,0 | B |
+----+---------------------+------+-------+------+

sql for each record join on same table excluding the source record and get the max record

I have a Budgets table that contains columns:
Id, ProjectCode, CreatedDate, IsReest, etc..
I have to find the records IsReest=1 in the Budgets table and for each matching projectcode I have to get the max(createddate), but excluding IsReest=1 record.
I need Id, ProjectCode, CreatedDate in the results as I need Id to join with other tables and ProjectCode and CreatedDate to display in the results.
So for example:
(I have used | delimiter to separate the values in the below tables)
Id | ProjectCode | CreatedDate | IsReest
------------------------------------------
1 | 12345 | 2016-10-16 | 1
2 | 12345 | 2016-10-14 | NULL
3 | 12222 | 2016-09-16 | NULL
4 | 12345 | 2016-10-15 | NULL
5 | 12333 | 2016-10-14 | NULL
6 | 12333 | 2016-10-15 | 1
Here records with Ids 1 and 6 has IsReest=1. I have to get max(CreatedDate) record for the same ProjectCode exluding IsReest=1 record.
So I have to get the results as:
Id | ProjectCode | CreatedDate | IsReset
-----------------------------------------
4 | 12345 | 2016-10-15 | NULL
5 | 12333 | 2016-10-14 | NULL
Record with ProjectCode 12222 should be ignored as it doesn't have a record with IsRest=1.
And record with Id 4 has the max(CreatedDate) in the group of records with the same ProjectCode and IsReest<>1.
Could some one please help me writing this query?
Thanks in advance.
It works using the below query. It may not be the best solution, but it works perfectly.
declare #Table table(ID int, ProjectCode int, CreateDate date, IsReest int)
insert into #Table Values
(1, 12345, '2016-10-16' , 1)
,(2, 12345, '2016-10-14' , NULL)
,(3, 12222, '2016-09-16' , NULL)
,(4, 12345, '2016-10-15' , NULL)
,(5, 12333, '2016-10-14' , NULL)
,(6, 12333, '2016-10-15' , 1)
select * from #Table t join
(
select projectcode, max(CreateDate) as CreateDate_Max from #Table where ProjectCode in
(
select ProjectCode from #Table bb where bb.IsReest = 1
) and IsReest is NULL
group by projectcode
) b
on b.projectcode = t.ProjectCode and b.CreateDate_Max = t.CreateDate
Try this:
declare #Table table(ID int, ProjectCode int, CreateDate date, IsReest int)
insert into #Table Values
(1, 12345, '2016-10-16' , 1)
,(2, 12345, '2016-10-14' , NULL)
,(3, 12222, '2016-09-16' , NULL)
,(4, 12345, '2016-10-15' , NULL)
,(5, 12333, '2016-10-14' , NULL)
,(6, 12333, '2016-10-15' , 1)
;WITH FLTR AS(
SELECT ProjectCode
FROM #Table
WHERE IsReest=1
)
, MX AS(
SELECT a.ProjectCode, MAX(a.CreateDate) AS CreateDate
FROM #Table as a
INNER JOIN FLTR as b on a.ProjectCode=b.ProjectCode
WHERE a.IsReest IS NULL
GROUP BY a.ProjectCode
)
SELECT a.*
FROM #Table AS A
INNER JOIN MX as b on a.ProjectCode=b.ProjectCode and a.CreateDate=b.CreateDate