MYSQL subquery results columns not as expected - mysql

I am trying to build a query that will build a output like this.
+-----------------+--------------+
| Name | patient appt |
+-----------------+--------------+
| Dharmick Ketan | 75 |
| See Ka Wai | 45 |
| Totoritis Susan | 25 |
| Seay Duval | 147 |
+-----------------+--------------+
The output that I go is this
+-----------------+--------------+
| Name | patient appt |
+-----------------+--------------+
| Dharmick Ketan | patient appt |
| See Ka Wai | patient appt |
| Totoritis Susan | patient appt |
| Seay Duval | patient appt |
+-----------------+--------------+
I was following the instructions here https://www.mysqltutorial.org/mysql-subquery/
My query is this
mysql> select concat(p.lname,' ' , p.fname) as 'Name',
-> 'patient appt'
-> from patient_data as p
-> where
-> p.financial_review_exp>'2019-07-01'
-> and
-> 'patient appt' = ( select count(*) from openemr_postcalendar_events e
-> where e.pc_pid = p.pid );
What I was expecting to happen was the alias 'patient appt' to be populated with the data from the nested select statement. I was thinking this would work because I am trying to produce multiple columns that are going to be populated by subqueries. All of the columns are counts of appointments in the calendar table.
So, does the 'patient appt' need to be a column in the patient_data table? If so, is there another way to produce the desired column data?

Put the correlated subquery directly in the select clause:
select concat(p.lname,' ' , p.fname) as name,
(select count(*) from openemr_postcalendar_events as e where e.pc_pid = p.pid) as patient_appt
from patient_data as p
where p.financial_review_exp > '2019-07-01'
Note: don't use single quotes for column aliases! They are meant for literal strings only. In MySQL, you can use backticks to quote identifiers - but better yet, use identifiers that do not require quoting, so you don't have to worry about that.

Related

Remove duplication of combination 2 columns

I want to remove all duplicates where combination of first name and last name is same
table users
mysql> select * from users;
+----+------------+-----------+
| id | LastName | FirstName |
+----+------------+-----------+
| 1 | Kowalski | Jan |
| 2 | Malinowski | Marian |
| 3 | Malinowski | Marian |
| 4 | Kowalski | Jan |
| 5 | Malinowski | Marian |
| 6 | Malinowski | Marian |
+----+------------+-----------+
I've created script
set #x = 1;
set #previous_name = '';
DELETE FROM users where id IN (SELECT id from (
select id, #previous_name,IF (CONCAT(FirstName, LastName) = #previous_name, #x:= #x + 1, IF(#previous_name:=CONCAT(FirstName, LastName), #x, IF(#x:=1, #x, #x))) as occurance
from users order by CONCAT(FirstName, LastName)
) AS occurance_table where occurance_table.occurance > 1);
but sql returns error
ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'JanKowalski'
I found a few similar questions, but solution were remove and word form syntax.
I want to prepare db for adding unique constrain for 2 columns, so I want to clear table from duplications.
What is best way to reach it?
I tried with the query mentioned in Answer section.
I believe that does not work. Instead I have modified the query to work
DELETE FROM users
WHERE id NOT IN
(
SELECT MIN(a.id)
FROM (SELECT * FROM users) a
GROUP BY a.LastName, a.FirstName
)
Please do correct me if I am wrong. #juergen
There is no need for a script. A single query is enough:
delete u1
from users u1
left join
(
select min(id) as min_id
from users
group by LastName, FirstName
) u2 on u1.id = u2.min_id
where u2.min_id is null
The subselect gets the lowest user id for each unique set of name. Joining to that you can delete everything else.

How to substitute the column values with a MySQL query

I am working with MySQL Workbench to get the table I am looking for. I am almost there. Here is the result of the query:
----------------------------------------------------------------------------
employee.manager_id | employee.id | employee.first_name | employee.last_name
----------------------------------------------------------------------------
null | 1 | Petra | Wallace
null | 3 | Peter | Willis
null | 5 | Michael | Best
1 | 2 | David | Lone
3 | 4 | Barbara | Grinder
5 | 6 | Anthony | Krone
Now, I want to replace the values of the column employee.manager_id with the following:
When the value is null, either leave it null or substitute it with the string "none"
When the value has a number, it references the number of the employee.id. For example, the value 1 in employee.manager_id represents employee.id number 1, who is Petra Wallace.
I would like to show in the employee.manager_id column, the employee.first_name and the employee.last_name, instead of a number. Anybody has any idea how to do it?
A left join retrieves a manager based on the JOIN criteria. If there isn't a manager, then all of the manager.* fields are NULL.
SELECT
COALESCE(manager.first_name,"none") as manager_first_name,
manager.last_name as manager_last_name,
employee.id,
employee.first_name,
employee.last_name
FROM employee
LEFT JOIN employee manager
ON employee.manager_id = manager.id
ORDER BY employee.manager_id
Try this:
SELECT
CASE WHEN employee.manager_id IS NULL THEN "NONE"
ELSE (SELECT CONCAT(e.first_name, ' ', e.last_name), e.id FROM employee e
WHERE e.id = employee.manager_id)
END AS case_generated_column,
employee.id, employee.first_name, employee.last_name FROM employee ORDER BY employee.manager_id;

Select latest value of another column based on a comparison between unique keys

What I'm trying to achieve is to fetch the latest date of another column based on the same msisdn (if there exists more than one msisdn that is linked to other imsis). (You can assume imsi is more of a unique column)
(Tables are simplified for demonstration purposes)
I've two tables like the following:
operator table
+--------+--------+---------------------+
| imsi | msisdn | last_accessed |
+--------+--------+---------------------+
| 74583 | 004442 | 2018-04-05 16:20:32 |
+--------+--------+---------------------+
| 94210 | 023945 | 2017-02-13 11:27:14 |
+--------+--------+---------------------+
| 59123 | 004442 | 2018-07-15 05:24:55 |
+--------+--------+---------------------+
| 61234 | 089923 | 2018-07-21 16:13:29 |
+--------+--------+---------------------+
customer table
+--------+--------------+---------------------+
| imsi | company_id | business_plan |
+--------+--------------+---------------------+
| 74583 | FEX | yearly |
+--------+--------------+---------------------+
| 94210 | AOH | trial |
+--------+--------------+---------------------+
| 59123 | BIOI | monthly |
+--------+--------------+---------------------+
| 61234 | OOX | simple |
+--------+--------------+---------------------+
The following result is what I aim for. If I search for 74583 it should return 2018-07-15 05:24:55.
+--------+--------------+---------------------+----------------------+
| imsi | company_id | business_plan | last_accessed_date |
+--------+--------------+---------------------+----------------------+
| 74583 | FEX | yearly | 2018-07-15 05:24:55 |
+--------+--------------+---------------------+----------------------+
The following query returns almost what I try to achieve but does not return the latest date according to the table above.
SELECT
cust.imsi,
cust.company_id,
cust.business_plan,
CASE
WHEN
(
SELECT MAX(subop.last_accessed)
FROM operator subop
WHERE subop.msisdn = op.msisdn
GROUP BY subop.msisdn
HAVING COUNT(*) > 1
)
THEN
op.last_accessed
ELSE
'Never'
END
AS last_accessed_date
FROM customer cust
INNER JOIN operator op
ON cust.imsi = op.imsi
WHERE cust.imsi = '74583';
We can try doing this using a correlated subquery in the select clause:
SELECT
c.imsi,
c.company_id,
c.business_plan,
(SELECT MAX(t.last_accessed) FROM operator t
WHERE t.msisdn = o.msisdn) last_accessed_date
FROM customer c
INNER JOIN operator o
ON c.imsi = o.imsi
WHERE c.imsi = '74583';
Follow the link below for a SQLFiddle demo.
Demo
This query will return the last_accessed_date for every imsi:
select
o1.imsi,
o1.msisdn,
max(o2.last_accessed) as last_accessed_date
from
operator o1 inner join operator o2
on o1.msisdn = o2.msisdn
group by
o1.imsi,
o1.msisdn
(I am joining the operators table with itself to get the last accessed date based on the msisdn column). Then you can join this query with the customer table:
select
c.imsi,
c.company_id,
c.business_plan,
coalesce(l.last_accessed_date, 'Never') as last_accessed_date
from
customer c left join (
select
o1.imsi,
o1.msisdn,
max(o2.last_accessed) as last_accessed_date
from
operator o1 inner join operator o2
on o1.msisdn = o2.msisdn
group by
o1.imsi,
o1.msisdn
) l on c.imsi = l.imsi
it can then be written in some different ways, but I think this is the easier to understand.
Please see a fiddle here http://sqlfiddle.com/#!9/0f080c/1
Try this
SELECT
cust.imsi,
cust.company_id,
cust.business_plan,
(
SELECT MAX(last_accessed) FROM operator AS a WHERE a.msisdn = op.msisdn
) AS last_accessed_date
FROM customer cust
INNER JOIN operator op
ON cust.imsi = op.imsi
WHERE cust.imsi = '74583'

How to SELECT top different value using order by matrics

i have a table like this
i want to get the row of each table that have min responsetime
i have tried this query :
select tablename,
index1,
index2,
min(responsetime)
from tableconf
group by tablename
order by responsetime asc
but it doesn't give what i want
the output that i want is
+------------------+------------------+--------+--------------+
| tablename | index1 | index2 | responsetime |
+------------------+------------------+--------+--------------+
| salesorderheader | TotalDue | NULL | 6.1555 |
| salesterritory | Name | NULL | 11.66667 |
| store | BusinessEntityId | Name | 3.6222 |
| previous | previous | NULL | 5.03333 |
| NONE | NONE | NULL | 5.6 |
+------------------+------------------+--------+--------------+
what query i should use for get the output that i want
Select the minimum date per table name. Use an IN clause on these to get the rows:
select *
from tableconf
where (tablename, responsetime) in
(
select tablename, min(responsetime)
from tableconf
group by tablename
);
(Edited from previous answer)
I don't know if all SQL syntax accept a comma separated where parameter. Another option building off of the highest voted answer right now utilizes a join:
select *
from tableconf t
inner join (
select tablename, min(responsetime) min_rt
from tableconf t2
group by tablename
) t3 on t.tablename = t2.tablename and t.responsetime = t2.min_rt

Removing duplicates based on one column, and keeping the row that has value in different column, and if there isn't any, keep lowest ID row

Using MySQL 5.7 on Google Cloud, I'm trying to deduplicate MySQL data based on an "EmailAddress" column, but some of the rows have a value in the "FullName" column and some of them don't. I want to keep the ones that have a value in the FullName column, but if none of the rows with that EmailAddress value a FullName value, then just keep the duplicate with the lowest ID number (first column - primary key).
I've finally broken it down into two separate queries, one to first remove the rows with no value in the FullName column IF there's another duplicate row that does have a value in the FullName column:
DELETE
FROM customer_info
WHERE id IN
(
SELECT *
FROM
(
SELECT c1.id
FROM customer_info c1
INNER JOIN customer_info c2 on c1.EmailAddress=c2.EmailAddress and c1.id!=c2.id
WHERE
(trim(c1.FullName)='' or c1.FullName is NULL)
and c2.FullName is not NULL
and length(trim(c2.FullName))!=0
) t
)
and another query to remove the rows with the bigger IDs where no value was found in the FullName column:
DELETE
FROM customer_info
WHERE id IN
(
SELECT *
FROM
(
SELECT c1.id
FROM customer_info c1
INNER JOIN customer_info c2 on c1.EmailAddress=c2.EmailAddress and c1.id>c2.id
) t
)
This "works", but not really. It worked one time when I left it running overnight for a smaller segment of the data, and when I woke up there was an error, but I looked at the data and it was complete.
Am I missing something in my query that's making it highly inefficient, or is it just par for the course for this type of query, and there's no optimization possible in my code that would make a tangible improvement? I've maxed out a Google Cloud SQL instance to their db-n1-highmem-32 size, with 32 GB of memory and 1000 GB of storage space, and it still chokes up and spits out a 2013 error after running for an hour. I need to do this for a total of a little over 3 million rows.
For example, this:
id | FullName | EmailAddress |
----------------------------------------------
1 | John Doe | john.doe#email.com |
2 | null | janedoe#box.com |
3 | null | billybob#bobby.com |
4 | null | john.doe#email.com |
5 | John Lennon | jlennon#yoohoo.com |
6 | null | james.smith#coolmail.com|
7 | null | billybob#bobby.com |
8 | Jane Doe | janedoe#box.com |
would result in this:
id | FullName | EmailAddress |
----------------------------------------------
1 | John Doe | john.doe#email.com |
3 | null | billybob#bobby.com |
5 | John Lennon | jlennon#yoohoo.com |
6 | null | james.smith#coolmail.com|
8 | Jane Doe | janedoe#box.com |
using exists() might be simpler in this situation
delete
from customer_info c
where (trim(c.FullName)='' or c.FullName is null)
and exists (
select 1
from customer_info i
where i.Email = c.EmailAddress
and trim(i.FullName)>''
)
delete
from customer_info c
where exists (
select 1
from customer_info i
where i.Email = c.EmailAddress
and i.id < c.id
)