SQL query for matching multiple values in the same column - mysql

I have a table in MySQL as follows.
Id Designation Years Employee
1 Soft.Egr 2000-2005 A
2 Soft.Egr 2000-2005 B
3 Soft.Egr 2000-2005 C
4 Sr.Soft.Egr 2005-2010 A
5 Sr.Soft.Egr 2005-2010 B
6 Pro.Mgr 2010-2012 A
I need to get the Employees who worked as Soft.Egr and Sr.Soft.Egr and Pro.Mgr. It is not possible to use IN or Multiple ANDs in the query. How to do this??

One way:
select Employee
from job_history
where Designation in ('Soft.Egr','Sr.Soft.Egr','Pro.Mgr')
group by Employee
having count(distinct Designation) = 3

What you might actually be looking for is relational division, even if your exercise requirements forbid using AND (for whatever reason?). This is tricky, but possible to express correctly in SQL.
Relational division in prosa means: Find those employees who have a record in the employees table for all existing designations. Or in SQL:
SELECT DISTINCT E1.Employee FROM Employees E1
WHERE NOT EXISTS (
SELECT 1 FROM Employees E2
WHERE NOT EXISTS (
SELECT 1 FROM Employees E3
WHERE E3.Employee = E1.Employee
AND E3.Designation = E2.Designation
)
)
To see the above query in action, consider this SQLFiddle
A good resource explaining relational division can be found here:
http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division

If you need to get additional information back about each of the roles (like the dates) then joining back to your original table for each of the additional designations is a possible solution:
SELECT t.Employee, t.Designation, t.Years, t1.Designation, t1.Years, t2.Designation, t2.Years
FROM Table t
INNER JOIN t2 ON (t2.Employee = t.Employee AND t2.Designation = 'Sr.Soft.Egr')
INNER JOIN t3 ON (t3.Employee = t.Employee AND t3.Designation = 'Soft.Egr')
WHERE t.Designation = 'Pro.Mgr';

Why not the following (for postgresql)?
SELECT employee FROM Employees WHERE Designation ='Sr.Soft.Egr'
INTERSECT
SELECT employee FROM Employees WHERE Designation ='Soft.Egr'
INTERSECT
SELECT employee FROM Employees WHERE Designation ='Pro.Mgr'
Link to SQLfiddle
I know this might not optimized, but I find this much much easier to understand and modify.

Try this query:
SELECT DISTINCT t1.employee,
t1.designation
FROM tempEmployees t1, tempEmployees t2, tempEmployees t3
WHERE t1.employee = t2.employee AND
t2.employee = t3.employee AND
t3.employee = t1.employee AND
t1.designation != t2.designation AND
t2.designation != t3.designation AND
t3.designation != t1.designation

Related

SQL query to compare a particular column to the average of the same coloum

My Schema is as follows
doctor (doctor_name, residence_address, postal_code, year_experience)
works (doctor_name, branch_name, annual_pay)
branch (branch_name, branch_address, postal_code)
patient (patient_name, doctor_name, branch_name)
I have been asked to retrieve the doctor_name whose annual pay is more than the average of all the doctors in a branch_name called "Singapore"
How do i do that in an sql query. Im using MySQL and so far i have tried this
SELECT doctor.doctor_name, doctor.residence_address
FROM doctor INNER JOIN works on doctor.doctor_name = works.doctor_name
WHERE avg(annual_pay)< annual pay
Try below query:
SELECT doctor_name
FROM doctor
INNER JOIN works ON doctor.doctor_name = works.doctor_name
WHERE annual_pay > (
SELECT avg(annual_pay)
FROM works
)
AND branch_name = 'Singapore'
One of possible solution is
select doctor_name
from
works,
(select avg(annual_pay) ap from works where branch_name='Singapore') ap
where
annual_pay>ap.ap
Just compare pay with calculated avg from a sub-query
SELECT doctor_name, annual_pay
FROM works
WHERE annual_pay > (SELECT AVG(annual_pay)
FROM works
WHERE branch_name = 'Singapore')
AND branch_name = 'Singapore'

Using select from another select in MySQL

I have the following query where I will have finally a 205 patient IDs to work with:
select
patient_id
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
I want to get all the 205 IDs and run them into other query to see how many diseases we have as cardio-vascular and then as respiratory disease.
My database structure is as the following:
What I want is to get for each patient id, what they are diagnosed at ONLY their first visit to the hospital (so here we will work with min(visit.date_of_visit))
The desired result for `diagnosis_name LIKE '%Cardio%':
E.g>:
Patients: 150 (Or something)
And the query is changed to get the respiratory info.
I tried the following for the Cardio diseases where I use select from select:
SELECT count(*)
FROM
(
select
min(visit.date_of_visit), visit_id, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
LEFT JOIN
consultation ON consultation.visit_id=vid.visit_id
LEFT JOIN
diagnosis ON diagnosis.diagnosis_id=consultation.diagnosis_id
WHERE diagnosis.diagnosis_name LIKE '%Cardio%'
The result was: 5 which is a wrong number.
This can be done easily with PHP and MYSQL together but this will exhaust the server by repeating the same query for 205 times and increment a counter. So the desired result should be only done with MySQL.
Data example:
Visit Table
visit_id= 1; date_of_visit=2018-03-03; visit_reason=Active; ...;
patient_id=1234;
visit_id= 2; date_of_visit=2018-03-04; visit_reason=Active; ...;
patient_id=1239;
visit_id= 3; date_of_visit=2018-03-07; visit_reason=Active; ...;
patient_id=1234;
Consultation Table
consultation_id=1; ...; diagnosis_id=12; visit_id=1;...;
consultation_id=2; ...; diagnosis_id=12; visit_id=2;...;
Diagnosis Table
diagnosis_id=12; diagnosis_name: hypertension (cardio disease);
diagnosis_id=13; diagnosis_name: renal disease
By running the query to see patients who came to hospital and that they were diagnosed as having cardio disease in their initial first visit, the result should be in the example as 2 as you can see from the example where patient_id=1234 had 2 visits but I need to know what he had in his first one.
You can use window functions in MySQL 8+. But in older versions you need to calculate the value some other way.
The question for you is what you are counting:
SELECT COUNT(*) as num_diagnoses, COUNT(DISTINCT patient_id) as num_patients
FROM visit v JOIN
(SELECT patient_id,
MIN(v.date_of_visit) as min_dov
FROM visit v
WHERE v.date_of_visit >= '2018-03-01' AND
v.date_of_visit < '2018-04-01' AND
v.visit_status = 'Active'
) vf
ON v.patient_id = vf.patient_id AND v.date_of_visit = vf.min_dov JOIN
consultation c
ON c.visit_id = v.visit_id JOIN
diagnosis d
ON d.diagnosis_id = c.diagnosis_id
WHERE d.diagnosis_name LIKE '%Cardio%';
When working with dates, it is best to compare column values directly to dates, rather than dissecting them.
BRO, it works fine. Test it now on the live scenario.
SELECT count(*)
FROM
(
select
min(visit.date_of_visit) first_date, patient_id, count(*) as patientId
FROM
visit
WHERE
month(visit.date_of_visit)=3
AND
year(visit.date_of_visit)=2018
AND
visit.visit_status='Active'
GROUP BY patient_id
) as vid
INNER JOIN visit b ON
B.patient_id = vid.patient_id AND
B.date_of_visit = vid.first_date and
month(B.date_of_visit)=3 AND
year(B.date_of_visit)=2018 AND
B.visit_reason='Active'
INNER JOIN consultation ON
consultation.visit_id = B.visit_id
INNER JOIN diagnosis ON
diagnosis.diagnosis_id = consultation.diagnosis_id AND
diagnosis.diagnosis_name LIKE '%Cardio%'

How to search where some data is in table 1 and other data is in table 3 with both having a UUID the same

I have 3 tables
For instance
Salestable
-ID
-variableB
-customerUUID
-variableC
Customertable
-customerUUID
-contractUUID
Contracttable
-contractUUID
-variableD
So I am currently doing a SQL Query on salestable
Like:
SELECT DISTINCT variableB FROM Salestable WHERE variableD = "blah";
How can I do this? Where I can find the contract associated with the current salestable?
A bit more info
They are all a 1:1 relationship - so Contracttable is tied to 1 Customertable which is tied to 1 salestable
There is a LOT of data in my database thousands of entries - this query does not run constantly but does need to run somewhat efficent.
SELECT a.*
FROM SalesTable a
INNER JOIN CustomerTable b
ON a.customerUUID = b.customerUUID
INNER JOIN Contracttable c
ON b.contractUUID = c.contractUUID
WHERE c.variableD = 'valueHere'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
If you sure the contract exists use this (othewise swap INNER FOR LEFT):
SELECT variableB, variableD
FROM Salestable t1
INNER JOIN Customertable t2 ON (t1.customerUUID = t2.customerUUID)
INNER JOIN Contracttable t3 ON (t3.contractUUID = t2.contractUUID)
WHERE variableD = "blah"
GROUP BY t1.variableB

Inner query is difficult to write

I have two tables:
customer with schema_id
Schema table has: schema_id, period, amt, updated_date
I need to take join of customer and schema but only retrieve the latest record joined and not the others.
customer table
cust_id name schema_id
1 ABC 1
Schema table
schema_id period amt updated_date
1 1 100 2010-4-1
1 2 150 2011-4-1
If you need the max(updated_date) for each schema_id, then you can use an subquery:
select c.cust_id, c.name, c.schema_id, s.period, s.amt, s.updated_date
from customer c
inner join
(
select s1.schema_id, s1.period, s1.amt, s1.updated_date
from `schemas` s1
inner join
(
select schema_id, max(updated_date) MaxDate
from `schemas`
group by schema_id
) s2
on s1.schema_id = s2.schema_id
and s1.updated_date = s2.maxdate
) s
on c.schema_id = s.schema_id
See SQL Fiddle with Demo
The subquery is then used in a join back to your table to return the rows that have the matching date and schema_id.
If I understood your problem, you need to take lastest register of the "schema".
I think you need to use max() function. So, try the query below:
select *
from customer c,
schema s
where c.schema_id = s.schema_id
and s.updated_date = ( select max(s2.updated_date)
from schema s2
where s2.schema_id = s.schema_id
)
Regards!
Edmilton

Complex SQL query. At least for me

I am trying to pull invoice data from my database based on a PatientID. I am trying to figure out which invoices belong to which patient. Here is the important parts of my structure.
Invoices Table
InvoiceNumber | DateInvoice | DueDate | StudyID | TypeInvoice
Patients Table
FirstName | LastName | PatientID
InvoiceFields
id | InvoiceNumber | PatientID |
I need make a query that lists the invoice table data based upon a PatientID. Below is the query that I attempted, but got no where with. Thank you for your time.
SELECT Distinct
invoicefields.InvoiceNumber,
invoices.DateInvoice
FROM `invoices`, `patients`, `invoicefields`
WHERE invoicefields.PatientID = patients.PatientID
and invoicefields.InvoiceNumber = invoicefields.InvoiceNumber
GROUP BY invoicefields.InvoiceNumber
SELECT InvT.InvoiceNumber, InvT.DateInvoice
FROM InvoiceTable InvT
INNER JOIN InvoiceFields InvF ON InvF.InvoiceNumber = InvT.InvoiceNumber AND InvF.PatientID = #PatientID
So pretty much since you only need data from the InvoiceTable and you indicate you have the PatientID. I propose you just join to the Cross Reference table InvoiceFields and use the PatientID column in that query to filter it down to what you need. I had a more complex example using an exist before I realized you didn't need anything from Patients.
You could use this if you need information on the Patient as well (Just put the needed columns in the Select)
SELECT InvT.InvoiceNumber, InvT.DateInvoice
FROM InvoiceTable InvT
INNER JOIN InvoiceFields InvF ON InvF.InvoiceNumber = InvT.InvoiceNumber AND InvF.PatientID = #PatientID
INNER JOIN Patient Pat ON Pat.PatientID = InvF.PatientID
You can put the #PatientID portion on the join for either Patient or InvoiceFields. There really shouldn't be a performance difference between either way if you indexes are right.
The Response to the Below Comment but where I can show it cleaner:
SELECT IT.InvoiceNumber
,IT.DateInvoice
FROM InvoiceTable InvT
WHERE EXISTS (SELECT InvF.PatientID
FROM InvoiceFields InvF
WHERE InvF.InvoiceNumber = InvT.InvoiceNumber
AND InvF.PatientID = #PatientID)
This will return all the rows for the patient from InvoiceTable and if InvoiceNumber is Unique will not have any duplicates. Though this way you only have access to InvoiceTable to return Data from. If you only want one put a TOP 1 on it:
SELECT TOP 1 IT.InvoiceNumber
,IT.DateInvoice
FROM InvoiceTable InvT
WHERE EXISTS (SELECT InvF.PatientID
FROM InvoiceFields InvF
WHERE InvF.InvoiceNumber = InvT.InvoiceNumber
AND InvF.PatientID = #PatientID)
SELECT * from invoices i
inner join invoicefields iFld
on i.invoiceNumber = iFld.invoiceNumber
inner join patients p
on iFld.patientID = p.patientID
and p.patientID = 1235125
This should get you started in the right direction at least. I'm not sure what columns you wanted to return and/or if there's any nulls in the tables. Nulls will affect which rows are returned