I got a MySQL Database where I store ship employees and their job experience. I got one table where I store the employees, one table where I store their previous jobs in the shipping department ( Type of Job , Years ) and another one table where I store their other previous jobs ( Type of Hob , Years ). All these are connected using the ID of the employee. When I fetch an employee I'd like to get the sum of his shipping and general experience, but the select query returns wrong sum for the general experience. I know this is cause by the multiple joins and because the tables are not joined properly, but I am not sure on how to fix this. Could you please help me?
P.S. I 'd like to do this with a single query.
Example of the query I use
SELECT id , name , SUM( s_exp.years ) , SUM ( g_exp.years )
FROM employees
LEFT JOIN s_exp ON employees.id = s_exp.id ,
LEFT JOIN g_exp ON employees.id = g_exp.id
GROUP BY employees.id
Maybe something like this:
SELECT id , name ,
(
SELECT
SUM(s_exp.years)
FROM
s_exp
WHERE
employees.id = s_exp.id
) AS s_total_years,
(
SELECT
SUM(g_exp.years)
FROM
g_exp
WHERE
employees.id = g_exp.id
) AS g_total_years,
FROM employees
Select id, sum(g_exp.years) GE, sum(s_exp.years) SE
From s_exp Natural Join g_exp
Where id = (Select id From employee Where name = ?)
group by id
Related
I have a user specific query which i need to run for all users.
I am struggling on how to replace the hard coded uuid with a reference or if it needs a different approach altogether?
select max(MaxDate), users.created_at
from (
select max(`moment`.`created_at`) as MaxDate
from `moment`
where `moment`.`user_uuid` = "7dd668af-241a-4176-a1da-f5689214b206"
union (
select max(`module`.`updated_at`) as MaxDate
from `module`
where `module`.`user_uuid` = "7dd668af-241a-4176-a1da-f5689214b206"
)
) as stuff, `users`
where `users`.`uuid` = "7dd668af-241a-4176-a1da-f5689214b206"
the end goal is to get the date a user was created and a date the same user last updated something and then get the avage time between them. But for all users not a single user.
Here is a general query which would report all users, sorted by user:
SELECT
u.user_uuid,
GREATEST(COALESCE(t1.max_created_at, t2.max_updated_at),
COALESCE(t2.max_updated_at, t1.max_created_at)) AS max_date
FROM users u
LEFT JOIN
(
SELECT user_uuid, MAX(created_at) AS max_created_at
FROM moment
GROUP BY user_uuid
) t1
ON u.user_uuid = t1.user_uuid
LEFT JOIN
(
SELECT user_uuid, MAX(updated_at) AS max_updated_at
FROM module
GROUP BY user_uuid
) t2
ON u.user_uuid = t2.user_uuid
ORDER BY
u.user_uuid;
If you want to restrict to a single user, you may still do so via a WHERE clause or via a WHERE IN clause for a group of users.
Note that there is a bit of a smell in your database design, because you have your user information strewn across multiple tables. My answer assumes that in general every user would appear in both tables, but maybe this is not the case.
Use group by
select `users`.`uuid`,max(MaxDate) as maxdate, min(users.created_at) as createddate
from (
select `moment`.`user_uuid`,max(`moment`.`created_at`) as MaxDate
from `moment`
group by `moment`.`user_uuid`
union
select `module`.`user_uuid`,max(`module`.`updated_at`) as MaxDate
from `module` group by `module`.`user_uuid`
) as stuff inner join `users` on `users`.`uuid`=stuff.user_uuid
group by `users`.`uuid`
What I have:
I have two table , first is user_faktorha save invoices data and second is u_payment save payment data .
What I want:
I want to group all data from this two table and have a result as one table with sum both table.
My two table with sample query's is on sqlfiddle : http://sqlfiddle.com/#!2/b9f9e/4
What's problem:
I try to solve this problem , but give wrong result each time , for example (can be see on sqlfiddle) , user/tell named as habib on give wrong sum(price) result.
habib's faktorhaprice = -508261 and habib's paymentprice = 648000 but sum result in main query have wrong data -7115654 and 13000000
what's the solution ?
(Updated) One way:
SELECT tell,SUM(FAKTORHAPRICE) FAKTORHAPRICE, SUM(PaymentPrice) PaymentPrice
FROM (SELECT tell, price as FAKTORHAPRICE, null PaymentPrice
from user_faktorha
union all
SELECT Username as tell, null as FAKTORHAPRICE, Price as PaymentPrice
FROM `u_payment` WHERE Active='1') sq
GROUP BY tell ORDER BY FAKTORHAPRICE ASC;
SQLFiddle here.
The essence of your problem here is that you are trying to relate to unrelated tables. Sure they have common data in the user name, but there is not a clean relation between them like an invoice id that can be used to relate the items together such that the OUTER JOIN wouldn't duplicate records in your result set. My suggestion would be to do the aggregation on each table individually and then join the results like this:
SELECT f.tell, f.faktorhaprice, p.paymentprice
FROM
(SELECT tell, SUM(price) AS faktorhaprice FROM user_faktorha GROUP BY tell) AS f
INNER JOIN
(SELECT username, SUM(price) AS paymentprice FROM u_payment GROUP BY username) AS p
ON f.tell = p.username
I have three tables as follows:
Contact, Custom_Field, Custom_Field_Value.
Each contact can have one Custom_Field_Value record for each Custom_Field. So there is a 1:many relationship between Contact and Custom_Field_Value but it isn't quite that simple.
Everything works fine - except for one edge case where I need to select Contacts that have a particular Custom_Field not set (i.e. no corresponding Custom_Field_Value record exists linking to the Contact and the Custom_Field). This is surprisingly difficult. I can't just use the normal "left join and look for NULL" approach because they may have a different custom field - but not the one I am looking for. I need to say "Where Custom_Field_ID=10" but I can't because the thing I'm looking for does not exist.
My line of thinking was heading in this direction, but I'm just tying myself in knots now:
Select ID, First_Name, Last_Name, CF_ID From
(
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact Inner Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Where Custom_Field_Value.CustomFieldID=23 Order By Contact.ID)
UNION
(Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
Order by Contact.ID)
) as A
Group BY `ID`, CF_ID ASC
I don't want to create blank records for every possibility because there could be millions of records and every time someone adds a custom field, the database would have to insert millions of corresponding blank records.
It would be really great if we could do this:
Select ID From thingy
EXCLUDE
Select * From thingy Where x = true
This is a nasty one, but I know there'll be someone out there who will love it:)
Okay, I think I have a better understanding now. I was trying to pull it off without a subquery, but I'm not sure if I can.
Can you try
Select Contact.ID, First_Name, Last_Name, Custom_Field_Value.ID as CFV_ID, Custom_Field_Value.CustomFieldID as CF_ID, TextValue
From Contact LEFT Join Custom_Field_Value on Contact.ID = Custom_Field_Value.ContactID
WHERE NOT EXISTS(SELECT * FROM Custom_Field_Value cfv2 WHERE cfv2.ContactID = Contact.ID AND cfv2.CustomFieldID=23)
Order by Contact.ID
The NOT EXISTS subquery should only return rows where the contact has no value for that field.
This is the crazy SQL I ended up with - created dynamically by users. Just publishing it in case its any use to anyone. (Any tips on optimisation are very welcome!):
The problem is that not only do I have to select missing dynamic records, I also have to join together Left Join queries into one result.
SELECT * FROM (
(SELECT * FROM Contact
WHERE (...some dynamic stuff...)
)
UNION All
(SELECT Contact.* FROM Contact Inner Join Contact_Campaign_Link ON Contact.ID=Contact_Campaign_Link.Contact_ID
WHERE ((Campaign_ID=31))
)
UNION All
(SELECT * FROM Contact
WHERE (CustomerID=3)
AND (NOT EXISTS
(SELECT * FROM Custom_Field_Value cfv2
WHERE (cfv2.ContactID = Contact.ID)
AND (cfv2.CustomFieldID =27) )) ORDER BY Contact.ID)
) As tbl
GROUP BY tbl.ID HAVING COUNT(*)=3 Order by ID
I have one table that contains first name and last name of employees in my company, and a field that determines whether they are still working for the company.
I have another table with contains list of tasks for the employees - It also contains two field with first and last name of the employee (- and yes, I know that's not a good structure).
I want to be able to find all employees that are still working for the company but have no tasks using MySQL query.
Any ideas?
SELECT *
FROM employees
WHERE still_working_for_company
AND NOT EXISTS (
SELECT TRUE
FROM tasks
WHERE tasks.firstname = employees.firstname
AND tasks.lastname = employees.lastname
)
You can try this--
select * from FirstTable where firstTable.employee='yes' and
firstTable.empid IN (select secondTbl.empId where firstTable.empid = secondTbl.empId)
Query is not tested and assume that your second table (task table) contain employee data only when task is assign.
Try this:
SELECT e.*
FROM emp e
LEFT JOIN emptask et ON e.firstname = et.firstname AND e.lastname = et.lastname
WHERE e.stillworks = 'y' AND et.taskid IS NULL
GROUP BY e.firstname, e.lastname
I'm stuck on a MySQL query. I have a temporary orders table with the following structure:
session_id
product_id
product_type -- 'institute','state','region','country'
For all institutes, states, regions and countries I have individual tables.
I want to create a MySQL query which fetches the data from my temp table and makes the join with the corresponding table depending upon product_type field.
If I use left join with 5 tables or use union it could be a really time consuming task; so I was looking for something different.
I would advise checking the answers in this question as they seem to match your specific problem https://stackoverflow.com/a/9327678/1213554
The short version though is that in order to be able to efficiently perform this request a database restructuring may well be required I'm afraid.
What you are looking for specifically is not possible, you'll have to use a UNION to do something along the lines of the following. As you say it will be a time consuming task though.
(
SELECT tempData.*
FROM tempData
INNER JOIN institutes
ON institutes.id = tempData.product_id
WHERE tempData.product_type = 'institute'
) UNION (
SELECT tempData.*
FROM tempData
INNER JOIN states
ON states.id = tempData.product_id
WHERE tempData.product_type = 'state'
) UNION (
SELECT tempData.*
FROM tempData
INNER JOIN regions
ON regions.id = tempData.product_id
WHERE tempData.product_type = 'region'
) UNION (
SELECT tempData.*
FROM tempData
INNER JOIN countries
ON countries.id = tempData.product_id
WHERE tempData.product_type = 'country'
)