Generating a unique ID from a SQL subquery - sql

I'm trying to insert the result of a subquery into a table, but the table I want to insert into has a unique primary ID. I want to take the max of the EID number and add 1 to any entry I'm trying to insert to the table.
Table I want to Insert Into:
----------------------------------------------------
EID (pk) | First Name | Employment Date
----------------------------------------------------
1 | John | 2016-01-01
2 | Joe | 2013-01-01
3 | Jill | 2012-01-01
4 | Jen | 2017-01-01
My subquery statement:
(SELECT FIRSTNAME, ORDERDATE as EMPLOYMENTDATE
FROM CUSTOMER, ORDER
WHERE CUSTOMER.id = ORDER.id
AND ORDERDATE >= DATE '2017-01-01')
The problem is inserting, as I don't have an unique ID to generate. This is on SQL Server
I am trying to insert something like this:
INSERT INTO EMPLOYEE(EID, FIRSTNAME, EMPLOYMENTDATE)
SELECT ??????WHAT GOES HERE??????, FIRSTNAME, ORDERDATE as EMPLOYMENTDATE
FROM CUSTOMER, ORDER
WHERE CUSTOMER.id = ORDER.id
AND ORDERDATE >= DATE '2017-01-01'

Assuming EID is identity, this is how:
INSERT INTO EMPLOYEE(FIRSTNAME, EMPLOYMENTDATE)
SELECT FIRSTNAME, ORDERDATE as EMPLOYMENTDATE
FROM CUSTOMER, ORDER
WHERE CUSTOMER.id = ORDER.id
AND ORDERDATE >= DATE '2017-01-01'

You're right, since you're using a subquery it would be like this:
INSERT INTO EMPLOYEE(EID, FIRSTNAME, EMPLOYMENTDATE)
SELECT
ISNULL((MAX(Emp.EID)+1),1) AS EID,
CustOrd.FirstName,
CustOrd.EmploymentDate
FROM
EMPLOYEE Emp,
(SELECT FIRSTNAME, ORDERDATE as EMPLOYMENTDATE
FROM CUSTOMER, ORDER
WHERE CUSTOMER.id = ORDER.id
AND ORDERDATE >= DATE '2017-01-01') CustOrd

Related

Query to find employees with no review or last review over 3 months ago

I have an issue with SQL part of my program. I have two tables Review and Employee. Employees can add reviews to each other but only once in every three months. Review table has this structure:
| ID | PerfomanceRating| Comment| ReviewDate| EmployeeID|
My goal is to retrieve all employees who has their latest review done more than 3 months ago. So my guess was that I need to get current date, subtract three months from it and compare to the MAX() date of each employee and if it is bigger - retrieve that employee from the database. Query:
SELECT Employee.ID, (FName + ' ' + LName) as Name, Review.ReviewDate, Email
FROM Employee
LEFT JOIN Review ON Employee.ID = Review.EmployeeId
WHERE SupervisorID = #empId
GROUP BY ReviewDate,Employee.ID,FName,LName,Email
HAVING ReviewDate IS NULL OR MAX(ReviewDate) < DATEADD(month, -3, GETDATE())
IS NULL - I have it here because employee can be freshly added and might not have any reviews. My problem is that this query gives me back employees with old reviews as well. Mean if employee had a review 4 months ago it will retrieve it ignoring my check for MAX(ReviewDate).
I feel that I'm missing something here but cannot get what exactly.
Example:
We have two employees in a table, one has two reviews and one has only one old review:
1 | ReviewTest3 ReviewTest3 | 2019-04-30 00:00:00.0000000
2 | ReviewTest2 ReviewTest2 | 2019-01-11 00:00:00.0000000
3 | ReviewTest2 ReviewTest2 | 2020-05-11 00:00:00.0000000
So MY query should show me only
1 | ReviewTest3 ReviewTest3 | 2019-04-30 00:00:00.0000000
AS ReviewTest2 ReviewTest2 has recent review. In my case it is
1 | ReviewTest3 ReviewTest3 | 2019-04-30 00:00:00.0000000
2 | ReviewTest2 ReviewTest2 | 2019-01-11 00:00:00.0000000
ReviewTest2 is also shown as it has review with an old date
For this kind of query keep the joins out of it... you're not looking to join the information, you just want to aggregate it, and use it for filtering. I find sub-queries far more straight-forward in such situations e.g.
select ID, (FName + ' ' + LName) as [Name], ReviewDate, Email
from (
select ID, SupervisorID, FName, LName, Email
, (select max(R.ReviewDate) from dbo.Review R where R.EmployeeID = E.ID) ReviewDate
from dbo.Employee E
) E
where SupervisorID = #empId
and (ReviewDate is null or ReviewDate < dateadd(month, -3, current_timestamp));
use window function row_number().
select
ID,
Name,
ReviewDate,
Email
from
(
SELECT
Employee.ID,
(FName + ' ' + LName) as Name,
Review.ReviewDate,
Email,
row_number() over (partition by Employee.ID order by convert(date, Review.ReviewDate) desc) as rnk
FROM Employee
LEFT JOIN Review ON Employee.ID = Review.EmployeeId
WHERE SupervisorID = #empId
AND (Review.ReviewDate is null or ReviewDate < DATEADD(month, -3, GETDATE()))
GROUP BY ReviewDate,Employee.ID,FName,LName,Email
) val
where rnk = 1
I have prepared sample data and tested in SQL Server.
DECLARE #employee table(Id int, FName varchar(30), LName varchar(30), Email varchar(255),SuperVisorId int)
Declare #review table (ID int, PerfomanceRating varchar(30), Comment varchar(30), ReviewDate datetime2, EmployeeID int)
insert into #employee VALUES(1,'Murugan','R','abc#xyz.com',999),(2,'Kandan','V','xyz#abc.com',999),(3,'Mark','Z','mark#mark.com',999)
insert into #review values(1,'review1','review1','2020-01-01',1),(2,'review2','review2','2020-05-05',1),
(3,'review1','review1','2020-01-01',2);
SELECT oe.ID, (oe.FName + ' ' + oe.LName) as Name, r.ReviewDate, Email
FROM #Employee AS oe
CROSS APPLY (
SELECT MAX(r.ReviewDate) FROM #review as r WHERE r.EmployeeId = oe.ID
GROUP BY r.EmployeeId
HAVING MAX(r.ReviewDate) < DATEADD(month, -3, GETDATE())
) as r(reviewDate)
WHERE SupervisorId = 999
-- Get Employees without review
UNION ALL
SELECT ID, (FName + ' ' + LName) as Name, NULL AS ReviewDate, Email
FROM #Employee as oe
WHERE NOT EXISTS(SELECT EmployeeId FROM #review WHERE EmployeeID = oe.Id)
AND SuperVisorId =999
Result set
+----+----------+-----------------------------+---------------+
| ID | Name | ReviewDate | Email |
+----+----------+-----------------------------+---------------+
| 2 | Kandan V | 2020-01-01 00:00:00.0000000 | xyz#abc.com |
| 3 | Mark Z | NULL | mark#mark.com |
+----+----------+-----------------------------+---------------+

Write Query to Iterating through employment data tables and performing sum of service duration

I'm working on employees database and trying to query employees result set with service duration of each employee. Service Duration will be calculated by subtracting Employment History table Ondate with APP date and TER date. there are two tables
Table 1 - Employees
Id - Primary key,
Name,
post,
Office,
Salary
Table 2 - Employment History
Id - Primary Key
ActionType,
OnDate,
EmployeeId - Foreign Key
There are two main action types:
APP - Appointment
TER - Termination
I need to calculate the duration of the Employee history if action types are APP and TER
Table 2 - (Employment History) present data like this
Id | ActionType | OnDate | EmployeeId
-----------------------------------------------
1 | APP |02/02/2011 | 1
2 | TER |03/05/2018 | 1
3 | APP |01/07/2018 | 1
4 | TER |02/06/2019 | 1
5 | APP |01/01/2008 | 2
6 | TER |02/03/2014 | 2
Currently i just joined two table with INNER JOIN. If an employee history has two job record then it will give duplicate record like this
EmpID | Name | OnDate | EndDate | Duration
----------------------------------------------
1 |emp1 |01/01/2016 | 02/06/2017 | 1.5 year
1 |emp1 |03/08/2017 | 31/12/2018 | 1.4 years
2 |emp2 |02/03/2015 | 05/04/2016 | 1.1 year
2 |emp2 |01/05/2017 | 19/03/2019 | 1.10 years
Instead of this i want to get duration of each employee record and sum each individual record and show it in one row
I want the result set like this
Id | Name | Service Duration
----------------------------
1 |emp1 | 2.9 years
2 |emp2 | 2.2 Year
is it possible to get result like this. please help
Try this:
select Id, sum(Duration)
from EmploymentHistory
group by Id
Please try:
declare #tbl as table (Id int, ActionType nvarchar(10), OnDate datetime, EmployeeId int)
insert into #tbl values (1,'APP','02/02/2011',1)
insert into #tbl values (2,'TER','03/05/2018',1)
insert into #tbl values (3,'APP','01/07/2018',1)
insert into #tbl values (4,'TER','02/06/2019',1)
insert into #tbl values (5,'APP','01/01/2008',2)
insert into #tbl values (6,'TER','02/03/2014',2)
select EmployeeId, sum(wspan)/12.0 [Service Duration]
from (
select
a.*, datediff(month, a.OnDate, b.OnDate) wspan
from #tbl a join
#tbl b on a.id=b.id-1 where a.ActionType='APP'
)x group by EmployeeId
You can group by EmpId in your query to get the sum of the Service Duration
;WITH EmploymentHistoryCTE AS
(
SELECT eh.EmpId,
SUM(DATEDIFF(month, eh.OnDate, eh.EndDate) % 12) AS 'ServiceDuration'
FROM EmploymentHistory eh
GROUP BY eh.EmpId
)
SELECT eh.EmpId,
e.Name,
eh.ServiceDuration
FROM EmploymentHistoryCTE eh
INNER JOIN Employees e
ON e.Id = eh.EmpId

SQL Server 2014 - How to get amount for Max Transaction Code

I have three tables Im joining to get results I need
Account Table
Contact Table
FinTrans table for Financial Transactions
With the below code, I get the AccountNumber, FullName, TransCode, TransNo and TransactionDate just fine and without errors. But now, I want to know the Amount for each Transaction Type from that list. But I seem to get multiple rows.
I have added extra code but commented those couple lines out to show what I want to add.
What do I need to add in the Group By section? I've tried adding TransNo, BusinessDay and then TransAmt. But I got multitple rows. I would really just like to show the TransAmt for that TransNo.
My code so far:
SELECT A.AccountNumber
,C.FirstName + ' ' + C.LastName Full_Name
,F.TransCode
--,F.TransAmt
,MAX(TransNo)TransNo
,Cast(Max(BusinessDay) as Date) TransactionDate
FROM FinTrans F
INNER JOIN Account A ON F.AccounttID = A.AccountId
INNER JOIN Contact C ON F.AccountID = C.AccountId
WHERE F.TransCode IN ('Payment', 'Adjustment')
AND F.AccountID IN (12345, 23456, 34567, 45678)
group by AccountNumber, FirstName, LastName, F.TransCode --, TransAmt
ORDER BY AccountNumber,TransactionDate
EDIT:
Adding the table sample data structure
Account Table Fields (A):
---------------------
AccountId
AccountNumber
Contact Table Fields (C):
---------------------
AccountId
FirstName
LastName
FinTrans Table fields (F):
------------------------
AccountId
TransCode
TransNo
TransAmt
BusinessDay
**A.AccountId = C.AccountId = F.AccountId**
FinTrans Table Data (F):
---------------------------------------------------
AccountId|TransCode |TransNo |TransAmt|BusinessDay|
--------------------------------------------------
12345 |Adjustment|A123456 | 545.26| 2018-04-11|
---------------------------------------------------
12345 |Payment |P234567 | 125.14| 2018-04-10|
---------------------------------------------------
12345 |Payment |P234566 | 99.26| 2018-04-08|
---------------------------------------------------
12345 |Adjustment|A356877 | 12.98| 2018-04-06|
---------------------------------------------------
Expected Result:
-------------------------------------------------------------------------
AccountNumber|Full_Name |TransCode | TransAmt|TransNo |BusinessDay|
-------------------------------------------------------------------------
A12345 |John Doe |Adjustment| 545.26|A123456 | 2018-04-11|
-------------------------------------------------------------------------
A12345 |John Doe |Payment | 125.14|P234567 | 2018-04-10|
-------------------------------------------------------------------------
Try this:
SELECT A.AccountNumber ,C.FirstName + ' ' + C.LastName
Full_Name,T.TransCode
,F.TransAmt
,T.TransNo
,T.TransactionDate
FROM (SELECT MAX(TransNo) TransNo,Cast(Max(BusinessDay) as Date)
TransactionDate, AccountId, TransCode FROM FinTrans WHERE TransCode IN
('Payment', 'Adjustment') AND AccountID IN (12345, 23456, 34567,
45678)
group by AccountId, TransCode) T
INNER JOIN FinTrans F ON T.AccountID = F.AccountId and T.TransNo=F.TransNo
INNER JOIN Account A ON T.AccountID = A.AccountId
INNER JOIN Contact C ON T.AccountID = C.AccountId
Have you tried adding the column to the transaction value?
SUM(F.TransAmt)
Look:
SELEC Name, Date, Value FROM x
Return
Jean 19-APR-2018 10
Jean 19-APR-2018 20
But
SELEC Name, Date, SUM(Value) FROM x GROUP BY Name
Will return
Jean 19-APR-2018 30

Get the results of a subquery in SQL

How do you create a join to get the latest invoice for all customers?
Tables:
- Invoices
- Customers
Customers table has: id, last_invoice_sent_at, last_invoice_guid
Invoices table has: id, customer_id, sent_at, guid
I'd like to fetch the latest invoice for every customer and, with that data, update last_invoice_sent_at and last_invoice_guid in the Customers table.
You want to use distinct on. For a query soring by customer_id and then by invoice, it would return the first row for each distinct value indicated in distinct on. That is the rows with * below:
customer_id | sent_at |
1 | 2014-07-12 | *
1 | 2014-07-10 |
1 | 2014-07-09 |
2 | 2014-07-11 | *
2 | 2014-07-10 |
So your update query could look like:
update customers
set last_invoice_sent_at = sent_at
from (
select distinct on (customer_id)
customer_id,
sent_at
from invoices
order by customer_id, sent_at desc
) sub
where sub.customer_id = customers.customer_id
#Konrad provided a flawless SQL statement. But since we are only interested in a single column, GROUP BY will be more efficient than DISTINCT ON (which is great to retrieve multiple columns from the same row):
UPDATE customers c
SET last_invoice_sent_at = sub.last_sent
FROM (
SELECT customer_id, max(sent_at) AS last_sent
FROM invoices
GROUP BY 1
) sub
WHERE sub.customer_id = c.customer_id;

Get list of unique records

I have the following table which lists the employees and their corresponding managers:
id | employeeid | managerid
1 | 34256 | 12789
2 | 21222 | 34256
3 | 12435 | 34256
.....
.....
What is the recommended way to list out all distinct employees(id) in a single list.
Note that all managers may not be listed under the employeeid column (as he may not have a manager in turn).
If I understand this correctly:
This will unite all distict Employee IDs avoiding duplicates from between the two column (UNION)
SELECT employeeid AS Employee
FROM tableA
UNION
SELECT managerid AS Employee
FROM tableA
This should d it :
SELECT DISTINCT employeeid FROM yourtablename
But seriously, by googling the keyword "distinct" you could have found out very easily yourself ! Or did I miss something out ?
SELECT id, employeeid, managerid
FROM
(SELECT yourtablename.*,
ROW_NUMBER() OVER (PARTITION BY managerid ORDER BY employeeid DESC) AS RN
FROM yourtablename) AS t
WHERE RN = 1
ORDER BY ID