Output isn't ordered properly - mysql

How to order the result by C, D, A, B and pincode chronologically?
Original result :
S Pincode
== =======
A 001
B 002
C 003
D 004
D 005
C 006
B 007
A 008
Expected result:
S Pincode
== =======
C 003
C 006
D 004
D 005
A 001
A 008
B 002
B 007
Code:
SELECT
id,
sector,
pincode
FROM
sh_av_spform
WHERE
type='ticket' and
status='new' and
date(`createdate`) = CURDATE()
ORDER BY
FIELD( sector, 'C','D','A','B' ) ASC
limit 5
Above SQL, Gives sometimes, not correctly ordered pincode in chronological sector
Invalid output i get such as:
S Pincode
== =======
C 003
C 006
D 005
D 004 <<< ???
A 001
A 008
B 007
B 002 <<< ???
Anyone know how to fix this?

You only order by one column. Add the second one too:
SELECT
id,
sector,
pincode
FROM
sh_av_spform
WHERE
type='ticket' and
status='new' and
date(`createdate`) = CURDATE()
ORDER BY
FIELD( sector, 'C','D','A','B' ) ASC,
pincode ASC

You didn't include pincode in your ORDER BY clause :
ORDER BY
FIELD( sector, 'C','D','A','B' ) , pincode
No need to write ASC as it is the default ordering.

Related

How to create MySQL query that converts rows to columns?

I'm creating an employee tracking app.
I have a MySQL table which is as follows:
ID
PersonID
TypeID
DateTime
1
001
IN
2022-09-01T13:21:12
2
001
OUT
2022-09-01T13:25:12
3
001
IN
2022-09-01T14:21:12
4
001
OUT
2022-09-01T14:25:12
5
002
IN
2022-09-03T13:21:12
6
002
OUT
2022-09-03T13:25:12
7
002
IN
2022-09-03T14:21:12
8
002
IN
2022-09-03T14:25:12
9
002
OUT
2022-09-03T14:25:12
10
002
OUT
2022-09-03T16:25:12
11
002
OUT
2022-09-03T17:25:12
12
002
IN
2022-09-04T16:25:12
13
002
IN
2022-09-05T17:25:12
I would like to create a view that returns records first sorted by PersonID and then by the ID but transforms the rows into columns.
Something like this:
PersonID
InID
In_DateTime
OutID
Out_DateTime
001
1
2022-09-01T13:21:12
2
2022-09-01T13:25:12
001
3
2022-09-01T14:21:12
4
2022-09-01T14:25:12
002
5
2022-09-03T13:21:12
6
2022-09-03T13:25:12
002
7
2022-09-03T14:21:12
null
null
002
8
2022-09-03T14:25:12
9
2022-09-03T14:25:12
002
null
null
10
2022-09-03T16:25:12
002
null
null
11
2022-09-03T17:25:12
002
12
2022-09-04T16:25:12
null
null
002
13
2022-09-05T17:25:12
null
null
Does anyone have an idea how to do this in MySQL?
Thanks for any suggestions.
Use window functions LEAD() or LAG() to get for each row its pair row, depending on its TypeID and do a left join of the results to the table:
WITH cte AS (
SELECT *,
CASE
WHEN TypeID = 'IN' AND LEAD(TypeID) OVER w = 'OUT' THEN LEAD(ID) OVER w
WHEN TypeID = 'OUT' AND LAG(TypeID) OVER w = 'IN' THEN LAG(ID) OVER w
END other_ID
FROM tablename
WINDOW w AS (PARTITION BY PersonID ORDER BY DateTime)
)
SELECT DISTINCT c.PersonID,
CASE WHEN c.TypeID = 'IN' THEN c.ID ELSE t.ID END InID,
CASE WHEN c.TypeID = 'IN' THEN c.DateTime ELSE t.DateTime END In_DateTime,
CASE WHEN c.TypeID = 'IN' THEN t.ID ELSE c.ID END OutID,
CASE WHEN c.TypeID = 'IN' THEN t.DateTime ELSE c.DateTime END Out_DateTime
FROM cte c LEFT JOIN tablename t
ON t.ID = c.other_ID
ORDER BY c.PersonID, COALESCE(In_DateTime, Out_DateTime);
See the demo.

add date to every name

hello please help me to solve this,, i am using mysql.. and I think, needing a full outer join to solve it,.
this is my query:
SELECT
e.NIK,
e.name,
a.dt
FROM
employee e
LEFT JOIN
attandence a
ON e.NIK=a.NIK
WHERE
month(a.dt)=12 AND year(a.dt)=2021
GROUP BY
e.NIK
this is the result:
NIK
name
dt
001
ana
23/12/2021
001
ana
24/12/2021
001
ana
26/12/2021
001
ana
27/12/2021
002
susi
23/12/2021
002
susi
24/12/2021
002
susi
25/12/2021
002
susi
26/12/2021
but i need to join it one more time with this table :
holidayTable
id
mark
dt
1
off_day
22/12/2021
2
chrismast
25/12/2021
I've tried using left/right/cross join, but it doesn't work
The result I want is like this:
NIK
name
dtWork
holiday
001
ana
null
22/12/2021
001
ana
23/12/2021
null
001
ana
24/12/2021
null
001
ana
null
25/12/2021
001
ana
26/12/2021
null
001
ana
27/12/2021
null
002
susi
null
22/12/2021
002
susi
23/12/2021
null
002
susi
24/12/2021
null
002
susi
25/12/2021
25/12/2021
002
susi
26/12/2021
null
You need a calendar table to achieve the output.
As of now I used union between holidaytable and attendance as Calendar.
You can achieve your desired result with below query.
SELECT e.nik,
e.name,
a.dt AS dtWork,
h.dt AS holiday
FROM employee e
CROSS JOIN(SELECT dt
FROM holidaytable
UNION
SELECT dt
FROM attendance)cal
LEFT JOIN attendance a
ON e.nik = a.nik
AND a.dt = cal.dt
LEFT JOIN holidaytable h
ON h.dt = cal.dt
WHERE a.dt IS NOT NULL
OR h.dt IS NOT NULL
ORDER BY nik ASC,
cal.dt ASC
SQLFiddle: Try it here
A union where the first part gets attendence and the second gets holidays (with as you thought a cross join) including a dummy column to assist ordering
select e.id,employeelastname,a.dt attendence,null holiday,a.dt as orderdt
from employees e
left join attendence a on a.nik = e.id
union
select e.id,employeelastname,null,h.dt holiday,h.dt
from employees e
cross join holidays h
order by id,orderdt;

How to join based on max timestamp in SQL?

So I have a df like this:
ID fruit
001 grapes
002 apples
002 mangos
003 bananas
004 oranges
004 grapes
And I want to join the following onto it:
ID store_time
001 2021-04-02 03:02:00.321
002 2021-04-02 02:02:00.319
002 2021-04-03 12:02:00.319
002 2021-04-04 13:02:00.312
003 2021-04-02 19:02:00.313
004 2021-04-02 15:02:00.122
004 2021-04-01 11:02:00.121
So all I want to do is join based on just the most recent timestamp. So leave the others behind and have only the number of rows as there are in the fruit df.
Final output:
ID fruit timestamp
001 grapes 2021-04-02 03:02:00.321
002 apples 2021-04-04 13:02:00.312
002 mangos 2021-04-04 13:02:00.312
003 bananas 2021-04-02 19:02:00.313
004 oranges 2021-04-02 15:02:00.122
004 grapes 2021-04-02 15:02:00.122
Aggregate in the 2nd table to get the most recent store_time for each ID and then join to the 1st table:
SELECT t1.ID, t1.fruit, t2.timestamp
FROM table1 t1
LEFT JOIN (
SELECT ID, MAX(store_time) timestamp
FROM table2
GROUP BY ID
) t2 ON t2.ID = t1.ID
I used a LEFT join just in case table2 does not contain all the IDs of table1.
If this is not the case then you can change it to an INNER join.
you need a subquery for max tme stamp
select a.id, a.fruit, b.max_time
from my_table_fruit a
inner join (
select id, max(store_time) max_time
from my_table_time
) b on b.id = a.id

Display Count of sales for employees

I have three tables. PersonalDetail, Employee and Orders. Personal details has data about names and stuff. Employee table has professional data. Orders have sales history.
Table PersonalDetail
personalID FirstName LastName
1 test test
2 test test
3 test test
4 test test
5 test test
Table Employee:
EmployeeID personalID hireDate Status
001 1 test test
002 2 test test
003 3 test test
004 4 test test
005 5 test test
and more data
Table Orders:
OrderID customerID EmployeeID ShipmentStatus
1 10 002 P
2 182 001 P
3 22 005 P
4 10 002 P
5 89 003 P
6 76 004 P
7 99 001 P
8 111 001 P
9 123 002 P
10 647 001 P
I want to get the end result as:
employeeID FirstName,LastName Count(sales to customers)
001 test test 4
002 test test 3
003 test test 1
004 test test 1
005 test test 1
So far, I have this:
SELECT e.employeeID, Concat (p.firstName,' ', p.lastName) AS Name, o.customerID
FROM Employee ((
INNER JOIN PersonalDetail ON e.personalID = p.personalID)
INNER JOIN Orders ON e.employeeID = o.employeeID)
ORDER BY employeeID;
This gives me the following result:
employeeID Name CustomerID
001 test test 182
001 test test 99
001 test test 111
001 test test 647
002 test test 10
002 test test 10
002 test test 123
003 test test 89
004 test test 76
005 test test 22
I know how to display employee name against each customer order but struggling with displaying the count of orders for a particular employee.
You can join and aggregate:
select
e.EmployeeID,
concat(e.FirstName, ',', e.LastName) employeeName,
count(*) no_sales
from employees e
inner join sales s on s.EmployeeID = e.EmployeeID
group by e.EmployeeID, e.FirstName, e.LastName
order by no_sales desc
To avoid error on 'order by' use the count itself:
select
E.EmployeeID,
concat(E.FirstName, ',', E.LastName) employeeName,
count(S.*) no_sales
from employees E
inner join sales S on S.EmployeeID = E.EmployeeID
group by E.EmployeeID, E.FirstName, E.LastName
order by count(S.*) desc

SQL Teradata - mark duplicate records in the column

So I know how to identify a dup row but now also need to identify the row linked to it and mark as duplicate.
Ex:
Row Name ID State Date Dup
---------------------------------------
001 Jim 001 NJ jan2020
002 Jim 001 NJ jan2020
003 Tan 002 NY feb2020
004 Allen 003 CA Feb2020
Output should like:
Row Name ID State Date Dup
---------------------------------------
001 Jim 001 NJ jan2020 Y
002 Jim 001 NJ jan2020 Y
003 Tan 002 NY feb2020 N
004 Allen 003 CA Feb2020 N
I can use partition using row_number but it will not flag the record 001 as Y. What could be an approach?
If you have a small number of columns, you can do something like this:
SELECT Row, Name, ID, State, Date,
CASE
WHEN COUNT(*) OVER(PARTITION BY Name, ID, State, Date) > 1 THEN 'Y'
ELSE 'N'
END AS Dup
FROM MyTable
This marks a given row as a duplicate based on the columns specified in the PARTITION BY expression. Also, be careful with your column names (i.e. Row, Date), as they may be reserved words.