Conditional ordering for Latin and English Names in SQLite - mysql

I have a table 'Employee' which has column DevId, Id, FName, FNamePinYin.
FName will have both Chinese and English contact names. Now as per requirement I could manage to get contacts in below order:
FName FNamePinYin
爱华 杨 AIHUA YANG
安国华 ANGUOHUA
Anguohua ANGUOHUA
Aihua Yang AIHUA YANG
爸 BA
波 小 BO BEI BI XIAO
毕慧 BIHUI
Bin Guo BIN GUO
Bihui BIHUI
Ba BA
Using below query:
Select FName, SortString
from Employee
where Id in (SELECT Id
FROM EMP1
WHERE '1' = DevId
ORDER BY FnamePinYin
LIMIT 500 OFFSET 0)
ORDER BY substr(FnamePinYin,1,1) , Lower(FName) DESC
Now the problem is that contact names are not sorted in ascending order.
Note: Here Lower(FName) DESC is required to get Chinese names to be displayed first in each alphabet's category.
My desired output:
FName FNamePinYin
爱华 杨 AIHUA YANG
安国华 ANGUOHUA
Aihua Yang AIHUA YANG
Anguohua ANGUOHUA
爸 BA
波 小 BO BEI BI XIAO
毕慧 BIHUI
Ba BA
Bihui BIHUI
Bin Guo BIN GUO
FNamePinYin is English equivalent of Chinese names.
Can anyone help me get the result I want?

Your question is still not entirely clear, but based on your statement that "both Chinese and English Name should be in Acceding order" "in each category (A-Z)", then the following should do what I think you want:
select *
from Employee
where Id in (SELECT Id
FROM PBAPL1
WHERE '1' = DevId
ORDER BY FnamePinYin
LIMIT 500 OFFSET 0)
order by substr(FNamePinYin,1,1), (substr(FName,1,1) < 'zz'), FName;

Related

Find the name of people who live at the same postal code, with flight delaying between 1 and 5

My current code is
select u.name , u.postalcode
FROM user u, flightdetails f, userscan s
WHERE deppdelay > 1 AND deppdelay <5 AND f.ticketid = s.ticketid AND s.userid = u.userid AND u.postalcode IN
(SELECT postalcode FROM user GROUP BY postalcode HAVING COUNT(postalcode) > 1)
ORDER BY postalcode;
The output is this
name
postalcode
Lee Jie Xuan
120338
Nicholas Sim
120338
Jasper Tan
120359
Nicholas Tan
120359
William Lee
120381
Brandon Cheong
120381
Choo Jia Yang Kiron
120453
Christopher Ang
120453
Ivan Goh
120460
Nelson Loo
120460
Kew Rui Hern
680623
Philbert Han
680767
Carter Reilly
680790
Phlip Wong
680790
Glen Ang
681660
Ignatius Ng
681660
However the expected outcome i Would like is duplicate values with distinct names. However, there are postal codes in my code that do not have duplicates.
Is there any recommended way to go about doing this?
P.S on the excel file, the postal codes that are displayed once has duplicate postal codes, however the other name has a flight delay not between 1 and 5.
Expected outcome:
name
postalcode
Lee Jie Xuan
120338
Nicholas Sim
120338
Jasper Tan
120359
Nicholas Tan
120359
William Lee
120381
Brandon Cheong
120381
Choo Jia Yang Kiron
120453
Christopher Ang
120453
Ivan Goh
120460
Nelson Loo
120460
Carter Reilly
680790
Phlip Wong
680790
Glen Ang
681660
Ignatius Ng
681660
I have actually managed to get rid of the single postal codes by using GROUP BY & HAVING COUNT (postalcode) > 1, however, because of the group by, I have distinct names missing.
select distinct u.name , u.postalcode
FROM user u, flightdetails f, userscan s
WHERE deppdelay > 1 AND deppdelay <5 AND f.ticketid = s.ticketid AND s.userid = u.userid AND u.postalcode IN
(SELECT postalcode FROM user GROUP BY postalcode HAVING COUNT(postalcode) > 1)
GROUP BY postalcode
HAVING COUNT(postalcode) >1;
Below is the o/p;
name
postalcode
Lee Jie Xuan
120338
Nicholas Tan
120359
William Lee
120381
Choo Jia Yang Kiron
120453
Ivan Goh
120460
Phlip Wong
680790
Ignatius Ng
681660
Sample data (user)
userid (key)
name
postalcode
phonenum
95559
Uriah Ferry
238859
83792072
32971
Mariah lupin
238859
81343214
Sample data (flightdetails)
ticketid (key)
depddelay (departure delay)
KED100001
2
KED100002
3
userscan (relationship)
ticketid
userid
KED100001
95559
KED100002
32971
Hope this does the trick
SELECT
usr.name , usr.postalcode
FROM flightdetails AS fd
INNER JOIN userscan AS uss ON fd.ticketid = uss.ticketid
INNER JOIN user AS usr ON uss.userid = usr.userid
WHERE fd.deppdelay > 1 AND fd.deppdelay <5
AND usr.postalcode IN
(
SELECT
usr.postalcode
FROM flightdetails AS fd
INNER JOIN userscan AS uss ON fd.ticketid = uss.ticketid
INNER JOIN user AS usr ON uss.userid = usr.userid
WHERE fd.deppdelay > 1 AND fd.deppdelay <5
GROUP BY usr.postalcode
HAVING COUNT(usr.postalcode) > 1
)
ORDER BY postalcode;
If the output format is less important, you can also do something like this, without the subquery:
SELECT
GROUP_CONCAT(usr.name) as usernames,
usr.postalcode
FROM flightdetails AS fd
INNER JOIN userscan AS uss ON fd.ticketid = uss.ticketid
INNER JOIN user AS usr ON uss.userid = usr.userid
WHERE fd.deppdelay > 1 AND fd.deppdelay <5
GROUP BY usr.postalcode
HAVING COUNT(usr.name) > 1
ORDER BY postalcode;
In that case, watch out for truncated results, MySQL will return 1024 chars in the GROUP_CONCAT by default

SQL nested query under WHERE

One of the test questions came by with following schemas, to look for the best doctor in terms of:
Best scored;
The most times/attempts;
For each medical procedures (in terms of name)
[doctor] table
id
first_name
last_name
age
1
Phillip
Singleton
50
2
Heidi
Elliott
34
3
Beulah
Townsend
35
4
Gary
Pena
36
5
Doug
Lowe
45
[medical_procedure] table
id
doctor_id
name
score
1
3
colonoscopy
44
2
1
colonoscopy
37
3
4
ulcer surgery
98
4
2
angiography
79
5
3
angiography
84
6
3
embolization
87
and list goes on...
Given solution as follow:
WITH cte AS(
SELECT
name,
first_name,
last_name,
COUNT(*) AS procedure_count,
RANK() OVER(
PARTITION BY name
ORDER BY COUNT(*) DESC) AS place
FROM
medical_procedure p JOIN doctor d
ON p.doctor_id = d.id
WHERE
score >= (
SELECT AVG(score)
FROM medical_procedure pp
WHERE pp.name = p.name)
GROUP BY
name,
first_name,
last_name
)
SELECT
name,
first_name,
last_name
FROM cte
WHERE place = 1;
It'll mean a lot to be clarified on/explain on how the WHERE clause worked out under the subquery:
How it worked out in general
Why must we match the two pp.name and p.name for it to reflect the correct rows...
...
WHERE
score >= (
SELECT AVG(score)
FROM medical_procedure pp
WHERE pp.name = p.name)
...
Thanks a heap!
Above is join with doctor and medical procedure and group by procedure name and you need doctor names with most attempt and best scored.
Subquery will join by procedure avg score and those who have better score than avg will be filtered.
Now there can be multiple doctor better than avg so taken rank by procedure count so most attempted will come first and then you taken first to pick top one

mysql order by multiple columns with if

SELECT s.name, s.mark, g.grade FROM students s, grades g
where g.grade = ( Select grade from grades where s.mark >= min_mark and s.mark <= max_mark)
order by IF(g.grade='F' or g.grade='E' or g.grade='D', (g.grade, s.mark), g.grade)
This is the mysql syntax that I am trying but not getting it to work.
The select works as intended, but I want to order the grades from A to F and on same grades I want to order the marks desc for A-C and asc for D-F
Hope it's clear what I want:
name grade mark
Ewan Black A 100
Ryan Richards B 90
Drake Porter C 78
Jamie Miller C 76
NULL D 67
NULL F 43
NULL F 54
As #Vatev noted, you can use a conditional statement to change the 2nd value being sorted. I would recommend using a CASE statement, as it's more compliant with SQL standards. Also, I would recommend you use the standard JOIN syntax, rather than the old-style (20-year-plus) joins. Also, you don't need a sub-query. So something like this:
select
students.name
,grades.grade
,students.mark
from students
inner join grades on
students.mark between grades.min_mark and grades.max_mark
order by
grades.grade
,case
when grades.grade in ('D', 'E', 'F')
then students.mark
else
100 - students.mark
end

MySQL: Select on GROUP BY only one row with certain criteria

I am having a table with documents where each document has a doc_id but on the same date for the same case_id I might be having two different language versions
doc_id case_id date lang
001-89259 1012/02 2008-11-04 FRA
001-144945 10122/04 2014-06-19 ENG
001-57558 10126/82 1988-06-21 ENG
001-62116 10126/82 1988-06-21 FRA
001-91708 10129/04 2009-03-10 FRA
001-116955 10131/11 2013-03-07 FRA
001-102676 10143/07 2011-01-11 FRA
001-104520 10145/07 2011-04-12 FRA
001-72756 10162/02 2006-03-09 FRA
001-72757 10162/02 2006-03-09 ENG
001-82198 10163/02 2007-09-06 ENG
001-57555 10208/82 1988-05-26 ENG
001-62113 10208/82 1988-05-26 FRA
What I want to do is to select the english version, if available, per case_id, date, otherwise keep the french. My output would then look like:
doc_id case_id date lang
001-89259 1012/02 2008-11-04 FRA
001-144945 10122/04 2014-06-19 ENG
001-57558 10126/82 1988-06-21 ENG -- keep only the english version
001-91708 10129/04 2009-03-10 FRA
001-116955 10131/11 2013-03-07 FRA
001-102676 10143/07 2011-01-11 FRA
001-104520 10145/07 2011-04-12 FRA
001-72757 10162/02 2006-03-09 ENG -- keep only the english version
001-82198 10163/02 2007-09-06 ENG
001-57555 10208/82 1988-05-26 ENG -- keep only the english version
How can I do it with MySQL?
UPDATE:
All answers give the correct result but I marked Görkem's as correct as IMO is the most elegant and straight-forward as of why it works.
I initially accepted Görkem's answer but for some reason it returned one wrong result that Strawberry pointed out. That leaves Strawberry's answer as the most elegant and correct
SELECT DISTINCT COALESCE(e.doc_id,f.doc_id) doc_id
, f.case_id
, f.date
, COALESCE(e.lang,f.lang) lang
FROM my_table f
LEFT
JOIN my_table e
ON e.case_id = f.case_id
AND e.date = f.date
AND e.lang = 'ENG';
SELECT
sorted.doc_id,
sorted.case_id,
sorted.date,
sorted.lang
FROM (
SELECT
doc_id,
case_id,
date,
lang
FROM tbl
ORDER BY FIELD(lang, 'ENG', 'FRA')
) sorted
GROUP BY sorted.case_id
If this SQL is required for some research, there is a way to get the expected result set:
Select SUBSTRING_INDEX(GROUP_CONCAT(doc_id ORDER BY lang ), ',', 1) doc_id, case_id, date, SUBSTRING_INDEX(GROUP_CONCAT(lang ORDER BY lang), ',', 1) lang from table group by case_id,date
SELECT
doc_id,
case_id,
date,
lang,
max(case lang when 'ENG' then 1 else 0 end)
FROM tbl
GROUP BY case_id

NOT DISTINCT query in mySQL

I have been asked to create a query for this on a simple employee database columns include:
ninumber - first name - last name - address - SuperVisorNiNumber
The employees and supervisors are all held in the same table and are referenced by their ninumbers. The query I've been asked to build is:
v. Find the NI Numbers, first and last names of employees and NI numbers of supervisors where the employees share that supervisor and both employees and supervisors work in department 8. You will refer to the employee relation twice was done in query vi of Practical 2. Your results should be presented in columns with the following titles ‘Employee NI number’, ‘First Name’, ‘Last Name’ and ‘Supervisor NI Number’.
Therefore I created this query:
SELECT e1.ninumber,
e1.fname,
e1.minit,
e1.lname,
e1.address,
e1.superNiNumber,
COUNT(*) AS nrOfOccurences
FROM employee AS e1,
employee AS e2
WHERE e1.dno = 8
AND e1.superNiNumber = e2.ninumber
AND e2.dno = 8
GROUP BY e1.superNiNumber
HAVING COUNT(*) > 1
I couldn't do a not distinct query to work out this part of the question - "where the employees share that supervisor". This query returns a grouping of the rows which in turn hides some of the rows I want to show.
My question is: Is my query correct for the question and can I do a NON DISTINCT query in mySQL to get the database to return all of the fields instead of grouping them together.
Reutrn results from my query
NInumber fname minit lname address supervisorNiNum number of occerences
666666601 Jill J Jarvis 6234 Lincoln, Antrim, UK 666666600 2
666666607 Gerald D Small 122 Ball Street, Letterkenny, IRL 666666602 3
666666604 Billie J King 556 WAshington, Antrim, UK 666666603 2
Thanks.
In your result table column description, I see no minit, address and number of occurrences. Therefore I would simplify your select to:
SELECT e1.ninumber,
e1.fname,
e1.lname,
e1.superNiNumber,
FROM employee AS e1,
employee AS e2
WHERE e1.dno = 8
AND e1.superNiNumber = e2.ninumber
AND e2.dno = 8
and (select count(*) from employee e3
where e3.superNiNumber = e1.superNiNumber) > 1;
The accepted answer is quite slow in performance. After a bit of searching I managed to produce a faster running equivalent:
SELECT e1.ninumber,
e1.fname,
e1.lname,
e1.superNiNumber
FROM employee AS e1, (SELECT superNiNumber,
COUNT(*) AS count
FROM employee
GROUP BY superNiNumber
HAVING count > 1) AS e2
WHERE e1.superNiNumber = e2.superNiNumber
Credit: http://www.programmingforums.org/thread14669.html