I've got 3 tables - entryrecord, employee and employee_entryrecord (linking table).
The query I'd like is for it to return the most recent (max time) inout record for each employee.
employee
id employee
1 John
2 Tom
entryrecord
id created_date inout
1 2016-07-22 16:01:38 1
2 2016-07-22 16:03:22 1
3 2016-07-22 16:05:22 2
4 2016-07-22 16:07:22 2
5 2016-07-22 16:09:22 1
I'd like the follow output
created_date employee inout entryrecordid
2016-07-22 16:09:22 John 1 5
2016-07-22 16:05:22 Tom 2 3
However, in the sqlfiddle below you can see it does not return the correct inout and entryrecordid values.
I've created a sqlfiddle to view what I've done.
SQL Fiddle
Any help would be great.
Thanks.
Please give it a try:
SELECT
finalALias.created_date,
E.employee,
finalALias.inout,
finalALias.id AS entryrecordid
FROM employee E
INNER JOIN
(
SELECT
*
FROM entryrecord entryR
INNER JOIN
(
SELECT
EER.employeeid,
MAX(created_date) max_time
FROM entryrecord ER
INNER JOIN employee_entryrecord EER ON ER.id = EER.entryrecordid
GROUP BY EER.employeeid
) t
ON t.max_time=entryR.created_date
) AS finalALias
ON E.id = finalALias.employeeid
ORDER BY finalALias.created_date DESC;
WORKING DEMO
Just a gentle reminder:
E -> employee
ER -> entryrecord
ERR -> employee_entryrecord
The problem is that grouping happens before ordering. You will have to do a sub query. You always want to try and keep your sub queries to a minimum as they put a heavy toll on the SQL server.
I changed your LEFT JOINS to INNER JOINS because it looked like you wanted to only get employees that were in the other tables.
SELECT
entryrecord.created_date,
employee.employee,
entryrecord.inout,
entryrecord.id
FROM
entryrecord
INNER JOIN
employee_entryrecord ON entryrecord.id = employee_entryrecord.entryrecordid
INNER JOIN
employee ON employee_entryrecord.employeeid = employee.id
WHERE
entryrecord.inout in (1,2)
AND entryrecord.id = (
SELECT er2.id
FROM employee_entryrecord eer2, entryrecord er2
WHERE eer2.employeeid = employee.id
AND er2.id = eer2.entryrecordid
ORDER BY er2.created_date DESC LIMIT 1
)
Related
I have a table that contains sales records:
Sale ID
EmployeeId(FK)
Employee 2
...
1
101
Null
...
2
102
Null
...
3
300
Bob
...
...
...
...
...
I have another table that contains employee records:
EmployeeId
EmployeeName
...
101
Amanda
...
102
Bob
...
...
...
...
300
cicilia
...
...
...
...
I'm trying to do a select where i get all sales and group them by employees for performance analysis. So far i managed to get right the employees and their sale counts and totals. The problem is the third column in my sales record is called employee2, it can be null as not every sale has another employee assisting. It is not indexed to the employee table unlike the second column.
So for example in my query below, the expected results should be Amanda has 1 salecount, 0 helpCount, meanwhile Boss has 1 salecount, 1 helpCount, and cicillia has 1 salecount, 0 helpcount. But im getting 1 salecount for all which is correct, but 0 helpcounts for bob. This is my query so far:
select employee.employee_id,
employee.employee_Name,
count(sale.sale_id) as saleCount,
sum(sale.grand_total) as totalSalesRevenue,
sum(CASE WHEN sale.employee2 = employee.employee_Name THEN 1
ELSE 0 END) as helperEmpCount
from employee
inner join sale on employee.employee_id = sale.employee_id
group by employee.employee_id;
The result set, where helpCounts should not be 0.
Im running a mysql 8.0 database.
Edit: I have found a workaround, albeit a very unefficient one. If i change my count to a nested select it works, but this decreases performance by quite a bit considering i have a lot of employees.
New query:
select employee.employee_id,
employee.employee_Name,
count(sale.sale_id) as saleCount,
sum(sale.grand_total) as totalSalesRevenue,
(select count(sale.employee2) from sale where sale.employee2= employee_Name) as helperEmpCount
from employee
inner join sale on employee.employee_id = sale.employee_id
group by employee.employee_id;
Any idea how to make it more efficient?
You can join the tables on either of the 2 conditions and use conditional aggregation:
SELECT e.employee_id,
e.employee_Name,
SUM(s.employee_id = e.employee_id) AS saleCount,
SUM(CASE WHEN s.employee_id = e.employee_id THEN s.grand_total ELSE 0 END) AS totalSalesRevenue,
SUM(s.employee2 = e.employee_Name) AS helperEmpCount
FROM employee e LEFT JOIN sale s
ON s.employee_id = e.employee_id OR s.employee2 = e.employee_Name
GROUP BY e.employee_id;
My table is:
id
student_id
exam_date
license
result
1
101
01-11-2020
B2
FAILED
2
102
15-11-2020
A
PASSED
3
103
22-11-2020
D
FAILED
4
101
01-10-2020
D
PASSED
5
104
01-12-2020
A
PASSED
6
103
29-11-2020
D
PASSED
7
101
01-12-2020
B2
PASSED
8
105
01-09-2020
B2
FAILED
9
104
01-11-2020
A
FAILED
10
105
01-11-2020
B2
PASSED
I need to select the results that would have the first result according to the exam date according to each student id and the license column. If the same student takes different license exam, these two results need to come up as well. But I need only one result row for each student id and license value.
The result should look like this:
id
student_id
exam_date
license
result
1
101
01-11-2020
B2
FAILED
2
102
15-11-2020
A
PASSED
3
103
22-11-2020
D
FAILED
4
101
01-10-2020
D
PASSED
8
105
01-09-2020
B2
FAILED
9
104
01-11-2020
A
FAILED
I've done the research and queries and so far I only got 1 row for student_id although the student takes two different license examination.
The following is my query:
SELECT scct_outer.id, scct_outer.stud_id, scct_outer.exam_date, scct_outer.license, scct_outer.result
FROM stud_cdl_comp_test AS scct_outer
INNER JOIN
(SELECT stud_id, MIN(exam_date) AS MinExamDate
FROM stud_cdl_comp_test AS scct
INNER JOIN stud AS s ON scct.stud_id = s.id
INNER JOIN agent_profile AS ap ON s.agent_profile_id = ap.id
GROUP BY stud_id) groupedscct
ON scct_outer.stud_id = groupedscct.stud_id
AND scct_outer.exam_date = groupedscct.MinExamDate
The problem with you original code is that it is missing a correlartion on the licences between the outer query and the subquery. You would phrase it as:
select s.*
from stud_cdl_comp_test s
inner join (
select student_id, licence, min(exam_date) as minexamdate
from stud_cdl_comp_test as scct
group by stud_id, licence
) s1 on s1.student_id = s.student_id and s1.license = s.license and s1.minexamdate = s.date
I have no idea what stud and agent_profile are, so I removed the from the query.
That said, this is not the method I would recommend - a simple and efficient option is to filter with a subquery:
select *
from stud_cdl_comp_test s
where s.exam_date = (
select min(s1.exam_date)
from stud_cdl_comp_test s1
where s1.student_id = s.student_id and s1.license = s.license
)
This can take advantage of an index on (student_id, license, exam_date).
Alternatively, you can use row_number(), available in MySL 8.0:
select *
from (
select s.*,
row_number() over(partition by student_id, licence order by exam_date) rn
from stud_cdl_comp_test s
) s
where rn = 1
Thinking that you are grouping by student_id in this case is almost incorrect in this case. What are actually grouping by is student + license. Let's call this key combination individual_license.
Here's what the solution will look like:
SELECT
st.id,
st.stud_id,
st.exam_date,
st.license,
st.result
FROM stud_cdl_comp_test AS st
INNER JOIN
(SELECT
MIN(exam_date) AS min_date,
st_inner.student_id,
st_inner.license
FROM stud_cdl_comp_test AS st_inner
GROUP BY st_inner.student_id, st_inner.license
) grouped_inner
ON grouped_inner.student_id = st.student_id
AND grouped_inner.license = st.license
AND grouped_inner.min_date = st.exam_date;
This should work.
I'm trying to get results from a join of 2 tables. Typically, not an issue, but I'm banging my head on this one. Basically, table1 (sales_dealers) is joined with table2 (sales_dealerEvents). Normally, easy-peasy. The problem is that I want to only get records from table2 if there are only 2 events (why I added the HAVING). But I need to get the value of the second event. With my query now, I can only get the value of the first event. It's like I need an ORDER BY EventID DESC on the joined table. It giving me ASC by default with this query.
Here is my query:
SELECT e.EventAction
, d.DealerID
, d.AgentID
, d.DealerName
, d.Email
, SUBSTRING_INDEX(d.PrimaryContactName, ' ', 1) AS FirstName
, d.State
, COUNT(e.EventID) AS EventCount
FROM sales_dealers d
JOIN sales_dealerEvents e
ON d.DealerID = e.DealerID
WHERE d.AgentID = 1
AND d.StatusID = 3
AND d.Email REGEXP '^[a-zA-Z0-9][a-zA-Z0-9._-]*#[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,4}$'
GROUP
BY d.DealerID
HAVING COUNT(e.EventID) = 2
ORDER
BY e.EventID DESC
Here is my Schema for the two tables (mysql version 5.7.27 )
sales_dealers
------------------
DealerID (int PK)
StatusID (int)
AgentID (int)
DealerName (varchar)
Email (varchar)
PrimaryContactName (varchar)
State (varchar)
sales_dealerEvents
------------------
EventID (int PK)
DealerID (FK)
AgentID (FK)
EventDateTime (datetime)
EventAction (longtext)
Here is sample data. Currently, the above query returns this:
Prospect Entry 784 1 Dealer Name One sales#dealer.com CA 2
Prospect Entry 782 1 Some other dealer hello#dealer.com MT 2
Prospect Entry 781 1 Dealer Store contact#dealer.com OK 2
I would like it to return this:
Initial Contact 784 1 Dealer One sales#dealer.com CA 2
Initial Contact 782 1 Some other dealer hello#dealer.com MT 2
Initial Contact 781 1 Dealer Store contact#dealer.com OK 2
Here is the same sample data of but showing the relationship of the one to many in sales_dealerEvents
sales_dealer
784 Dealer Name One
sales_dealerEvents
1000 784 1 Prospect Entry 2020-06-02 01:00:00
1010 784 1 Initial Contact 2020-07-03 01:00:00
I'm feeling I might have to do this in a subquery to sort the event so the second event is first. Not sure. I might also need to match criteria of that second event too.
UPDATE - Here is my SQL fiddle
http://sqlfiddle.com/#!9/ef6f2c/2
As you can see with the fiddle.. all event records returned are 'prospect entry'.. which were the first entries for 'events' for those. Each have 2. The second is 'Initial Contact'. Their date and EventID is after the 'prospect entry'.
Hope the below query helps and you can see the demo here: http://sqlfiddle.com/#!9/ef6f2c/37/0
SELECT
EventAction,
DealerID,
AgentID,
DealerName,
Email,
FirstName,
State,
EventID
from
(
SELECT
e.EventAction,
d.DealerID,
d.AgentID,
d.DealerName,
d.Email,
SUBSTRING_INDEX(d.PrimaryContactName, ' ', 1) AS FirstName,
d.State,
e.EventID as EventID
FROM
sales_dealers d
JOIN
sales_dealerEvents e
ON d.DealerID = e.DealerID
WHERE
d.AgentID = 1
AND d.StatusID = 3
AND d.Email REGEXP '^[a-zA-Z0-9][a-zA-Z0-9._-]*#[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,4}$'
ORDER BY
e.EventID DESC
)
a
GROUP BY
DealerID
HAVING
COUNT(EventID) = 2
This sounds like you want window functions:
select . . .
from sales_dealers d join
(select e.*,
row_number() over (partition by e.DealerID order by e.EventDateTime) as seqnum
from sales_dealerEvents e
) e
on e.DealerID = d.DealerID and e.seqnum = 2
where . . .
Note this gets data from the second event even if there are more than two events. That seems consistent with the question, but it is easy enough to use count(*) as a window function to do further filtering.
I have two tables, one is Table_Log for when user will update the data then it will stored one data into Table_Log, and another table is main registration table: Table_Registration and I need based on updatedDate of Table_Log data should come first order by desc.
Table_Log:
RegId Name updatedDate
-----------------------------------
3 jj 2018-03-21 13:30:04.497
3 jj 2018-03-20 13:30:04.497
Table_Registration
RegId Name Email SubDate
--------------------------------------------------------
2 kk kk#gmail.com 2018-03-01 15:30:04.497
3 jj jj#gmail.com 2018-02-26 15:30:04.497
1 Raj raj#gmail.com 2018-02-30 13:30:04.497
I need this output as my result:
RegId Name Email SubDate
--------------------------------------------------------
3 jj jj#gmail.com 2018-02-26 15:30:04.497
2 kk kk#gmail.com 2018-03-01 15:30:04.497
1 Raj raj#gmail.com 2018-02-30 13:30:04.497
I tried below query but some duplication is coming.
select r.*
from Table_Registration r
left join Table_Log a
on a.RegId = r.RegId
order by isnull(a.updatedDate, r.SubDate) desc
select r.*
from Table_Registration r
left join Table_Log a
on a.RegId = r.RegId
order by isnull(a.updatedDate, r.SubDate) desc
In the above code, you left join to Table Log. This will give you one row per row of tablelog, which is why you are getting duplication. You need to process table_Log in some way so that you are only getting the most recent row per registration, and then join to that. Something like this
select r.*
from Table_Registration r
left join (Select RegId, Max(updateDate) as updateDate from Table_Log Group By RegId) a
on a.RegId = r.RegId
order by isnull(a.updatedDate, r.SubDate) desc
kon
id | name
1 alex
2 peter
3 john
ticket
id | amount | kon_id | package
122 13 1 234
123 12 1 234
124 20 2 NULL
125 23 2 235
126 19 1 236
I would like to get a list of all contacts with the sum of the amount, except tickets, where the package entry is NULL.
My problem is, that I only get the contacts which have a ticket, because of the WHERE clause.
SELECT
kon.id,
kon.name,
SUM(ticket.amount)
FROM kon LEFT JOIN ticket ON kon.id = ticket.kon_id
WHERE ticket.package IS NOT NULL
GROUP BY kon.id
At the moment, the output looks like this
1 alex 44
2 peter 23
but it should look like this
1 alex 44
3 john NULL
2 peter 23
I use a MySQL Server.
Is it possible to solve this?
Replace Where with AND
SELECT
kon.id,
kon.name,
SUM(ticket.amount)
FROM kon LEFT JOIN ticket ON kon.id = ticket.kon_id AND ticket.package IS NOT NULL
GROUP BY kon.id
Check This.
SELECT
k.id,
k.name ,
coalesce (SUM(t.amount) ,0)
FROM kon k LEFT JOIN
( select id,amount,kon_id,package from ticket where package is not null ) t
ON k.id = t.kon_id
GROUP BY k.id, k.name
OutPut :
Begin Tran
Create Table #Kon (id INt , name Nvarchar(255))
Insert into #Kon
Select 1,'alex' UNION ALL
Select 2,'peter' UNION ALL
Select 3,'john'
Create Table #Ticket (id int,amount int,Kon_Id Int,Package Int)
INSERT INTO #Ticket
SELECT 122,13,1,234 UNION ALL
SELECT 123,12,1,234 UNION ALL
SELECT 124,20,2,NULL UNION ALL
SELECT 125,23,2,235 UNION ALL
SELECT 126,19,1,236
SELECT K.id, Name,SUM(amount) amount
FROM #Kon k
LEFT JOIN #Ticket T ON K.id=T.Kon_Id
GROUP BY K.id,Name
RollBAck Tran
Generally, "ticket.package IS NOT NULL" is wrong condition: your query becomes inner join from left join. If ticket.package should be NOT NULL to add from amount, it should be not in condition, but inside SUM agregate function.
working example for MS SQL
SELECT
kon.id,
min(kon.name),
SUM(case when package is NULL then 0 else ticket.amount end)
FROM #kon kon LEFT JOIN #ticket ticket ON kon.id = ticket.kon_id
GROUP BY kon.id
Answer from Mr. Bhosale is right too, but for big tables will have worse performance (the reason is subquery)
the following query return your expected result
SELECT
kon.id,
kon.name,
SUM(ticket.amount) as 'amount'
FROM kon LEFT JOIN ticket ON kon.id = ticket.kon_id
GROUP BY kon.id, kon.name
attached image shows the result
I figured out the fastest way to solve the problem. It takes about 0.2s compared to the other solutions (2s - 2min). The CAST is important, otherwise the summation of double variables is wrong (float string problem).
SELECT
kon1,
kon2,
SUM(CAST(kon3 AS DECIMAL(7,2)))
FROM (
SELECT k.id kon1, k.name kon2, t.amount kon3 FROM kon as k
LEFT JOIN ticket t ON k.id = t.ticket_kon
WHERE t.package IS NOT NULL
UNION ALL
SELECT k.id kon1, k.name kon2, NULL kon3 FROM kon k WHERE) t1
GROUP BY kon1, kon2