Find name of employees hired on different joining date - sql

I wrote a query to find the employess hired on same date.
this is the query
select a.name,b.name,a.joining,b.joining from [SportsStore].[dbo].[Employees] a,
[SportsStore].[dbo].[Employees] b where a.joining = b.joining and a.name>b.name
Then a question popped into my mind. How do i find those employess only who were hired on different dates? I tried something like this
select a.name,b.name,a.joining,b.joining from [SportsStore].[dbo].[Employees] a,
[SportsStore].[dbo].[Employees] b where a.joining != b.joining and a.name>b.name
but then i realized this doesnt make sense . I thought about a sub query but it wont work either because we are selecting from two tables.
So i searched and could not find anything.
So the question is how do we "Find name of employees hired on different joining date?"

JOIN the Employees table with a subquery that counts the joining dates.
where j.num = 1
returns employees hired on different dates
where j.num > 1
returns employees hired on same date
select e.id, e.name, e.joining
from [SportsStore].[dbo].[Employees] e
inner join (select joining, count(*) num
from [SportsStore].[dbo].[Employees]
group by joining) j
on j.joining = e.joining
where j.num = 1;
+----+------+---------------------+
| id | name | joining |
+----+------+---------------------+
| 1 | abc | 01.01.2017 00:00:00 |
+----+------+---------------------+
| 2 | def | 01.01.2017 00:00:00 |
+----+------+---------------------+
| 5 | mno | 01.01.2017 00:00:00 |
+----+------+---------------------+
+----+------+---------------------+
| id | name | joining |
+----+------+---------------------+
| 3 | ghi | 02.01.2017 00:00:00 |
+----+------+---------------------+
| 4 | jkl | 03.01.2017 00:00:00 |
+----+------+---------------------+
Can check it here: http://rextester.com/OOO96554

If you just need the names (and not the list of different hiring dates), the following rather simple query should do the job:
select id, name
from employee
group by id, name
having count(distinct joining) > 1

after getting the answer , I have another way to get the same result . Here it is. I Hope its helpful to others and someone might explain which approach is better and in what scenario .
select name,joining from [SportsStore].[dbo].[Employees] where joining not in
(
select joining
from [SportsStore].[dbo].[Employees]
group by joining
having count(*)=1
)

Related

Alias Reference Date_Diff Days. Need to Parse or create temp table with dates?

Below I have the tables and query which output the below
Table1
EmployeeID | StartDateTimestamp | CohortID | CohortName
---------- | ------------------ | -------- | ----------
1 | 20080101 01:30:00 | 1 | Peanut
1 | 20090204 01:01:00 | 2 | Apple
2 | 20190107 05:52:14 | 1 | Peanut
3 | 20190311 02:35:26 | 2 | Apple
Employee
EmployeeID | HireStartName | StartDateTimestamp2
---------- | ------------- | -------------------
1 | HiredStart | 20080501 01:30:00
1 | DeferredStart | 20090604 01:01:00
2 | HiredStart | 20190115 05:52:14
3 | HiredStart | 20190330 02:35:26
Query
select
t.cohortid,
min(e.startdatetimestamp2) first,
max(e.startdatetimestamp2) last
from table1 t
inner join employee e on e.employeeid = t.employeeid
group by t.cohort_id
Output
ID | FIRST | LAST
1 |20190106 12:00:05 |20180214 03:45:12
2 |20180230 01:45:23 |20180315 01:45:23
My attempt:
SELECT DATE_DIFF(first, last, Day), ID, max(datecolumn1) first, min(datecolumn1) last
Error: Unrecognized name.
How do I enter the reference alias first and last in a Date_Diff?
Do I need to derive a table?
Clarity: Trying to avoid inputting in the dates, since I am looking to find the date diff of both first and last columns for as many rows as there is data.
This answer has been discussed here: Date Difference between consecutive rows
DateDiff has deprecated, and now it is Date_Diff (first, last, day)
Then I tried:
SELECT ID, DATE_DIFF(PARSE_DATE('%y%m%d',t.first), PARSE_DATE('%y%m%d',t.last), DAY) days
FROM table
Failed to parse input string "20180125 01:00:05"
Tried this
SELECT CohortID, date_diff(first,last,day) as days
FROM (select cohortid,min(startdatetimestamp2) first,
max(startdatetimestamp2) last
FROM employee
JOIN table1 on table1.employeeid = employee.employeeid
group by cohortid)
I get days not found on either side of join
Regarding your first question about using aliases in a query, there are some restriction where to use them, specially in the FROM, GROUP BY and ORDER BY statements. I encourage you to have a look here to check these restrictions.
About your main issue, obtaining the date difference between two dates. I would like to point that your timestamp data, in both of your tables, are actually considered as DATETIME format in BigQuery. Therefore, you should use DATETIME builtin functions to get the desired results.
The below query uses the data you provided to obtain the aimed output.
WITH
data AS
(
SELECT
t.cohortid AS ID,
PARSE_DATETIME('%Y%m%d %H:%M:%S', MIN(e.startdatetimestamp2)) AS first,
PARSE_DATETIME('%Y%m%d %H:%M:%S', MAX(e.startdatetimestamp2)) AS last
FROM
`test-proj-261014.sample.table1` t
INNER JOIN
`test-proj-261014.sample.employee` e
ON
e.employeeid = t.employeeid
GROUP BY t.cohortid
)
SELECT
ID,
first,
last,
DATETIME_DIFF(last, first, DAY ) AS diff_days
FROM
data
And the output:
Notice that I created a temp table to format the fields StartDateTimestamp and StartDateTimestamp2, using the PARSE_DATETIME(). Afterwards, I used the DATETIME_DIFF() method to obtain the difference in days between the two fields.

How do I get the next record based on a condition using a SQL Query?

I have a car hire table which records all the dates a car is on hire Onhire and when it's returned Offhire. I've been asked to provide the next or follow on hire company name in the results table but I'm not sure how to do it. The hire table is structured as follows:
---------------
| Hire |
---------------
| Id |
| CarId |
| Onhire |
| Offhire |
| HireCompany |
|-------------|
If I run a basic select against that table I see the following data. I've added a WHERE to pull back a specific car that is still on hire and has a follow on hire shortly after (I am using UK date formatting).
Id | CarId | Onhire | Offhire | HireCompany
-------------------------------------------------------
10 | 272 | 2019-01-01 | 2019-03-01 | Company A
11 | 272 | 2019-03-02 | 2019-04-01 | Company B
-------------------------------------------------------
As you can see, the car is currently on hire until 01/03/2019 but after that, it is going on hire to Company B on the 02/03/2019. I need my query to show that the car is on hire at the moment but in a column called ForwardHire (or whatever) show the NEXT company that has it on hire as well as a column that shows the next hire start date.
So, my query would produce the following desired result:
Id | CarId | Onhire | Offhire | ForwardHire | ForwardHireDate
---------------------------------------------------------------------------
10 | 272 | 2019-01-01 | 2019-03-01 | Company B | 2019-03-02
Note: I am already aware of how to return a single result from my Hire
table using an outer apply, advice which I got in a different thread.
I hope my question has made sense and that someone can help. In terms of SQL queries, this is a first for me so any advice and guidance are appreciated.
Are you looking for lead function ? :
SELECT h.*
FROM (SELECT h.*,
LEAD(HireCompany) OVER (PARTITION BY CarID ORDER BY Id) AS ForwardHire,
LEAD(Onhire) OVER (PARTITION BY CarID ORDER BY Id) AS ForwardHireDate
FROM Hire h
) h
WHERE ForwardHire IS NOT NULL AND ForwardHireDate IS NOT NULL;
Using OUTER APPLY:
SELECT
H.*,
T.ForwardHire,
T.ForwardHireDate
FROM
Hire AS H
OUTER APPLY (
SELECT TOP 1 -- Just the next record
ForwardHire = F.HireCompany,
ForwardHireDate = F.OnHire
FROM
Hire AS F
WHERE
H.CarId = F.CarId AND -- With the same car
F.OnHire > H.OffHire -- With later OnHire
ORDER BY
F.OnHire ASC -- Sorted by OnHire (closeste one first)
) AS T
Do you just want lead()?
select h.*,
lead(h.hirecompany) over (partition by h.carid order by h.onhire) as next_hirecompany
from hire h;
Note: this will return the next company, even if there are gaps. If you want the "adjacent" next company, then I'd recommend a left join:
select h.*, hnext.hirecompany as next_hirecompany
from hire h left join
hire hnext
on hnext.carid = h.carid and
hnext.onhire = dateadd(day, 1, h.offhire);
Self join the hire table to the row that has the next onhire date:
select
h1.*,
h2.hirecompany ForwardHire
h2.onhire ForwardHireDate
from hire h1 left join hire h2
on
(h2.carid = h1.carid)
and
(h2.onhire = (select min(onhire) from hire where carid = h1.carid and onhire > h1.offhire) )
where
h1.carid = 272
and
curdate() between h1.onhire and h1.offhire

SQL Where Query to Return Distinct Values

I have an app that has the built in initial Select option and only allows me to enter from the Where section. I have rows with duplicate values. I'm trying to get the list of just one record for each distinct value but am unsure how to get the statement to work. I've found one that almost does the trick but it doesn't give me any rows that had a dup. I assume due to the = so just need a way to get one for each that matches my where criteria. Examples below.
Initial Data Set
Date | Name | ANI | CallIndex | Duration
---------------------------------------------------------
2/2/2015 | John | 5555051000 | 00000.0001 | 60
2/2/2015 | John | | 00000.0001 | 70
3/1/2015 | Jim | 5555051001 | 00000.0012 | 80
3/4/2015 | Susan | | 00000.0022 | 90
3/4/2015 | Susan | 5555051002 | 00000.0022 | 30
4/10/2015 | April | 5555051003 | 00000.0030 | 35
4/11/2015 | Leon | 5555051004 | 00000.0035 | 10
4/15/2015 | Jane | 5555051005 | 00000.0050 | 20
4/15/2015 | Jane | 5555051005 | 00000.0050 | 60
4/15/2015 | Kevin | 5555051006 | 00000.0061 | 35
What I Want the Query to Return
Date | Name | ANI | CallIndex | Duration
---------------------------------------------------------
2/2/2015 | John | 5555051000 | 00000.0001 | 60
3/1/2015 | Jim | 5555051001 | 00000.0012 | 80
3/4/2015 | Susan | 5555051002 | 00000.0022 | 30
4/10/2015 | April | 5555051003 | 00000.0030 | 35
4/11/2015 | Leon | 5555051004 | 00000.0035 | 10
4/15/2015 | Jane | 5555051005 | 00000.0050 | 20
4/15/2015 | Kevin | 5555051006 | 00000.0061 | 35
Here is what I was able to get but when i run it I don't get the rows that did have dups callindex values. duration doesn't mattern and they never match up so if it helps to query using that as a filter that would be fine. I've added mock data to assist.
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and callindex in
(SELECT callindex
FROM table
GROUP BY callinex
HAVING COUNT(callindex) = 1)
Any help would be greatly appreciated.
Ok with the assistance of everyone here i was able to get the query to work perfectly within SQL. That said apparently the app I'm trying this on has a built in character limit and the below query is too long. This is the query i have to use as far as the restrictions and i have to be able to search both ID's at the same time because some get stamped with one or the other rarely both. I'm hoping someone might be able to help me shorten it?
use Database
select * from tblCall
WHERE
flddate between '4/15/15 00:00' and '4/15/15 23:59'
and fldAgentLoginID='1234'
and fldcalldir='incoming'
and fldcalltype='external'
and EXISTS (SELECT * FROM (SELECT MAX(fldCallName) AS fldCallName, fldCallID FROM tblCall GROUP BY fldCallID) derv WHERE tblCall.fldCallName = derv.fldCallName AND tblCall.fldCallID = derv.fldCallID)
or
flddate between '4/15/15 00:00' and '4/15/15 23:59'
and '4/15/15 23:59'
and fldPhoneLoginID='56789'
and fldcalldir='incoming'
and fldcalltype='external'
and EXISTS (SELECT * FROM (SELECT MAX(fldCallName) AS fldCallName, fldCallID FROM tblCall GROUP BY fldCallID) derv WHERE tblCall.fldCallName = derv.fldCallName AND tblCall.fldCallID = derv.fldCallID)
If the constraint is that we can only add to the WHERE clause, I don't think it's possible, due to there being 2 absolutely identical rows:
4/15/2015 | Jane | 5555051005 | 00000.0050
4/15/2015 | Jane | 5555051005 | 00000.0050
Is it possible that you can add HAVING or GROUP BY to the WHERE? or possibly UNION the SELECT to another SELECT statement? That may open up some additional possibilities.
Maybe with an union:
SELECT *
FROM table
GROUP BY Date, Name, ANI, CallIndex
HAVING ( COUNT(*) > 1 )
UNION
SELECT *
FROM table
WHERE Name not in (SELECT name from table
GROUP BY Date, Name, ANI, CallIndex
HAVING ( COUNT(*) > 1 ))
From your sample, it seems like you could just exclude rows in which there was no value in the ANI column. If that is the case you could simply do:
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and ANI is not null
If this doesn't work for you, let me know and I can see what else I can do.
Edit:
You've made it sound like the CallIndex combined with the Duration is a unique value. That seems somewhat doubtful to me, but if that is the case you could do something like this:
use Database
SELECT * FROM table
WHERE Date between '4/15/15 00:00' and '4/15/15 23:59'
and cast(callindex as varchar(80))+'-'+cast(min(duration) as varchar(80)) in
(SELECT cast(callindex as varchar(80))+'-'+cast(min(duration) as varchar(80))
FROM table
GROUP BY callindex)
There are two keywords you can use to get non-duplicated data, either DISTINCT or GROUP BY. In this case, I would use a GROUP BY, but you should read up on both.
This query groups all of the records by CallIndex and takes the MAX value for each of the other columns and should give you the results you want:
SELECT MAX(Date) AS Date, MAX(Name) AS Name, MAX(ANI) AS ANI, CallIndex
FROM table
GROUP BY CallIndex
EDIT
Since you can't use GROUP BY directly but you can have any SQL in the WHERE clause you can do:
SELECT *
FROM table
WHERE EXISTS
(
SELECT *
FROM
(
SELECT MAX(Date) AS Date, MAX(Name) AS Name, MAX(ANI) AS ANI, CallIndex
FROM table
GROUP BY CallIndex
) derv
WHERE table.Date = derv.Date
AND table.Name = derv.Name
AND table.ANI = derv.ANI
AND table.CallIndex = derv.CallIndex
)
This selects all rows from the table where there exists a matching row from the GROUP BY.
It won't be perfect, if any two rows match exactly, you'll still have duplicates, but that's the best you'll get with your restriction.
In your data, why not just do this?
SELECT *
FROM table
WHERE Date >= '2015-04-15' and Date < '2015-04-16'
ani is not null;
If the blank values are only a coincidence, then you have a problem just using a where clause. If the results are full duplicates (no column has a different value), then you probably cannot do what you want with just a where clause -- unless you are using SQLite, Oracle, or Postgres.

SQL: Select distinct sum of column with max(column)

I have a salary table like this:
id | person_id | start_date | pay
1 | 1234 | 2012-01-01 | 3000
2 | 1234 | 2012-05-01 | 3500
3 | 5678 | 2012-01-01 | 5000
4 | 5678 | 2013-01-01 | 6000
5 | 9101 | 2012-09-01 | 2000
6 | 9101 | 2014-04-01 | 3000
7 | 9101 | 2011-01-01 | 1500
and so on...
Now I want to query the sum of the salaries of a specific month for all persons of a company.
I already have the ids of the persons who worked in the specific month in the specific company, so I can do something like WHERE person_id IN (...)
I have some problems with the salaries query though. The result for e.g. the month 2012-08 should be:
10000
which is 3500+5000+1500.
So I need to find the summed up pay value (for all persons in the IN clause) for the maximum start_date <= the specific month.
I tried various INNER JOINS but it's been a long day and I can't think straight at the moment.
Any hint is highly appreciated.
You need to get the active record. This following does this by calculating the max start date before the month in question:
select sum(s.pay)
from (select person_id, max(start_date) as maxstartdate
from salary
where person_id in ( . . . ) and
start_date < <first day of month of interest>
group by person_id
) p join
salary s
on s.person_id = p.person_id and
s.maxstartdate = p.start_date
You need to fill in the month and list of ids.
You can also do this with ranking functions, but you don't specify which SQL engine you are using.
You have to use group by for these things....
select person_id,sum(pay) from salary where person_id in(...) group by person_id
may it will helps you.....

MIN() Function in SQL

Need help with Min Function in SQL
I have a table as shown below.
+------------+-------+-------+
| Date_ | Name | Score |
+------------+-------+-------+
| 2012/07/05 | Jack | 1 |
| 2012/07/05 | Jones | 1 |
| 2012/07/06 | Jill | 2 |
| 2012/07/06 | James | 3 |
| 2012/07/07 | Hugo | 1 |
| 2012/07/07 | Jack | 1 |
| 2012/07/07 | Jim | 2 |
+------------+-------+-------+
I would like to get the output like below
+------------+------+-------+
| Date_ | Name | Score |
+------------+------+-------+
| 2012/07/05 | Jack | 1 |
| 2012/07/06 | Jill | 2 |
| 2012/07/07 | Hugo | 1 |
+------------+------+-------+
When I use the MIN() function with just the date and Score column I get the lowest score for each date, which is what I want. I don't care which row is returned if there is a tie in the score for the same date. Trouble starts when I also want name column in the output. I tried a few variation of SQL (i.e min with correlated sub query) but I have no luck getting the output as shown above. Can anyone help please:)
Query is as follows
SELECT DISTINCT
A.USername, A.Date_, A.Score
FROM TestTable AS A
INNER JOIN (SELECT Date_,MIN(Score) AS MinScore
FROM TestTable
GROUP BY Date_) AS B
ON (A.Score = B.MinScore) AND (A.Date_ = B.Date_);
Use this solution:
SELECT a.date_, MIN(name) AS name, a.score
FROM tbl a
INNER JOIN
(
SELECT date_, MIN(score) AS minscore
FROM tbl
GROUP BY date_
) b ON a.date_ = b.date_ AND a.score = b.minscore
GROUP BY a.date_, a.score
SQL-Fiddle Demo
This will get the minimum score per date in the INNER JOIN subselect, which we use to join to the main table. Once we join the subselect, we will only have dates with names having the minimum score (with ties being displayed).
Since we only want one name per date, we then group by date and score, selecting whichever name: MIN(name).
If we want to display the name column, we must use an aggregate function on name to facilitate the GROUP BY on date and score columns, or else it will not work (We could also use MAX() on that column as well).
Please learn about the GROUP BY functionality of RDBMS.
SELECT Date_,Name,MIN(Score)
FROM T
GROUP BY Name
This makes the assumption that EACH NAME and EACH date appears only once, and this will only work for MySQL.
To make it work on other RDBMSs, you need to apply another group function on the Date column, like MAX. MIN. etc
SELECT T.Name, T.Date_, MIN(T.Score) as Score FROM T
GROUP BY T.Date_
Edit: This answer is not corrected as pointed out by JNK in comments
SELECT Date_,MAX(Name),MIN(Score)
FROM T
GROUP BY Date_
Here I am using MAX(NAME), it will pick one name if two names were found with the same goal numbers.
This will find Min score for each day (no duplicates), scored by any player. The name that starts with Z will be picked first than the name that starts with A.
Edit: Fixed by removing group by name