Link for Er Diagram:
I want to get data from the child tables.
Eg. I need location, equipments, language, service for all user_id. There are multiple values for location, equipment, language and service for a given user_id.
I tried the following code:
SELECT user_detail.user_id , user_detail.name , user_equipment.equipment , user_location.location , user_service.service , user_language.language
from user_detail
INNER JOIN user_equipment on user_detail.user_id = user_equipment.user_id
INNER JOIN user_location on user_detail.user_id = user_location.user_id
INNER JOIN user_service on user_detail.user_id = user_service.user_id
INNER JOIN user_language on user_detail.user_id = user_language.user_id;
Now the problem is, if there are three location for a user_id I get three row, is there any way I get all location in same row?
You are looking for this "GROUP_CONCAT", your query would look like this:
SELECT user_detail.user_id ,
user_detail.name,
GROUP_CONCAT(user_equipment.equipment SEPARATOR ',') as equipments,
GROUP_CONCAT(user_location.location SEPARATOR ',') as locations,
GROUP_CONCAT(user_service.service SEPARATOR ',') as services,
GROUP_CONCAT(user_language.language SEPARATOR ',') as languages
FROM user_detail
INNER JOIN user_equipment on user_detail.user_id = user_equipment.user_id
INNER JOIN user_location on user_detail.user_id = user_location.user_id
INNER JOIN user_service on user_detail.user_id = user_service.user_id
INNER JOIN user_language on user_detail.user_id = user_language.user_id;
GROUP BY user_detail.user_id
In situations where I can't use a GROUP_CONCAT call, I would do the select, then join them in some resulting code. I am unsure what application language you are using, but for something like php:
$select = $query(); //Returns the SELECT results
for($i = 0; $i < count($select); $i++){
for($a = 0; $a < count($select); $a++){ //Double loop to check the entire list
if($a !== !i){ //No point in selecting the same row and comparing it
$location_count = 0;
if($select[$a]['user_id'] === $select[$i]['user_id']){
$locationref = 'location_'.$location_count++;
$select[$i][$locationref] = $select[$a]['location'];
}
}
}
}
Just my thoughts - untested but the general principle is there.
You can reduce multiple lines to single lines for each user, by grouping by user_id. The GROUP_CONCAT function will enable you to see all values of location in the group - like so:
SELECT user_detail.user_id ,
user_detail.name ,
user_equipment.equipment ,
GROUP_CONCAT(user_location.location SEPARATOR ',') AS user_locations ,
user_service.service ,
user_language.language
from user_detail
INNER JOIN user_equipment on user_detail.user_id = user_equipment.user_id
INNER JOIN user_location on user_detail.user_id = user_location.user_id
INNER JOIN user_service on user_detail.user_id = user_service.user_id
INNER JOIN user_language on user_detail.user_id = user_language.user_id
GROUP BY user_detail.user_id;
Note that this assumes there will always be one (and only one) equipment, service and language record for each user - if there can be more than one of each then you should use GROUP_CONCAT for their values (with a DISTINCT qualifier), while if the user might not have corresponding records the join to the relevant table should be changed to a LEFT OUTER JOIN.
Related
In the picture is my table situation right now:
The central table in this case right now is tblJob, here is everything defined what I need (not all in the picture).
The address table needs to return 2 values (1 of the company and 1 of the job itself). The only thing I need to do right now is to add the company address (the job address is already in my query) My query already looks like this:
SELECT
tblJob.jobID,
tblJob.amount AS jobAmount,
tblJob.extraInfo AS jobExtraInfo,
tblJob.views AS jobViews,
tblJob.description AS jobDescription,
tblJob.dateCreated AS jobDateCreated,
tblJobFunction.jobFunctionID,
tblJobFunction.jobFunction,
tblAddress.zipcode AS jobAddress,
tblAddress.city AS jobCity,
tblAddress.street AS jobStreet,
tblAddress.number AS jobNumber,
tblAddress.bus AS jobBus,
tblCountry.countryID AS jobCountryID,
tblCountry.country AS jobCountry,
tblCountry.areaCode AS jobAreaCode,
tblCompany.companyID,
tblCompany.name,
tblCompany.email,
tblCompany.GSM,
tblCompany.phoneNumber,
tblCompany.photoURL AS companyPhotoURL,
tblCompany.VATNumber,
tblCompany.websiteURL,
tblEvent.eventID,
tblEvent.event,
tblEvent.description AS eventDescription,
tblEvent.startDate AS eventStartDate,
tblEvent.endDate AS eventEndDate,
tblEvent.facebookURL,
tblEvent.photoURL AS eventPhotoURL,
tblEvent.views AS eventViews,
tblEvent.dateCreated AS eventDateCreated
FROM tblJob
JOIN tblAddress ON tblAddress.addressID = tblJob.addressID
JOIN tblCountry ON tblAddress.countryID = tblCountry.countryID
JOIN tblJobFunction ON tblJob.jobFunctionID =
tblJobFunction.jobFunctionID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
LEFT JOIN tblEvent ON tblJob.eventID = tblEvent.eventID
Now the question is: how can I add the address from the company in the same query?
Use the address table as many times as you need it, but each time you must give it a new alias:
FROM tblJob
JOIN tblAddress ON tblAddress.addressID = tblJob.addressID
JOIN tblCountry ON tblAddress.countryID = tblCountry.countryID
JOIN tblJobFunction ON tblJob.jobFunctionID = tblJobFunction.jobFunctionID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
JOIN tblAddress a2 ON a2.addressID = tblCompany.addressID
LEFT JOIN tblEvent ON tblJob.eventID = tblEvent.eventID
perhaps more like this:
SELECT JobAddress.street, CompanyAddress.street
FROM tblJob
JOIN tblAddress JobAddress ON JobAddress.addressID = tblJob.addressID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
JOIN tblAddress CompanyAddress ON CompanyAddress.addressID = tblCompany.addressID
This query is taking between 20-40 seconds to run. I need to speed it up greatly if possible.
SELECT DISTINCT a.category, a.key
FROM system_permissions AS a, system_permission_to_role AS b,
system_user_to_role AS c, system_users AS d
WHERE
(
(
a.system_permission_id=b.system_permission_id
AND (b.system_role_id=c.system_role_id || c.system_role_id = 0)
AND a.system_permission_id NOT IN (
SELECT system_permission_id FROM system_permission_exclusions AS f
WHERE d.system_user_id=f.system_user_id
)
AND c.system_user_id=d.system_user_id
)
OR a.system_permission_id IN (
SELECT system_permission_id
FROM system_permission_inclusions AS g
WHERE d.system_user_id=g.system_user_id
)
)
AND d.ldap_objectguid = '?';
The reason behind doing it this way is that I am creating exclusion and inclusion tables for permissions that fall outside of the standard defined roles, so first I need to exclude ones that are part of the role but exist in the exclusion table, then I need to add ones that are NOT part of their role, but exist in the inclusion table.
I am open to the idea of redesigning the tables also.
Does this work?
SELECT DISTINCT P.category, P.key
FROM system_users U
LEFT OUTER JOIN system_permission_inclusions PI ON PI.system_user_id = U.system_user_id
INNER JOIN system_user_to_role UR ON UR.system_user_id = U.system_user_id
INNER JOIN system_permission_to_role PR ON PR.system_role_id = UR.system_role_id
INNER JOIN system_permissions P ON P.system_permission_id = PR.system_permission_id OR P.system_permission_id = PI.system_permission_id
WHERE U.ldap_objectguid = '?'
AND P.system_permission_id NOT IN (SELECT system_permission_id FROM system_permission_exclusions WHERE system_user_id = U.system_user_id)
I'm trying to use the value of a column called children_ids inside a subquery:
SELECT hotels.id,
hotels.hotel,
hotels.country,
hotels.corrected,
hotels.children_type,
hotels.children_ids as children_ids,
(SELECT SUM(trx_input.count) FROM hotels LEFT JOIN trx_input ON hotels.trx_id = trx_input.id WHERE hotels.id IN (children_ids)) as count_children,
trx_input.count
FROM hotels
LEFT JOIN trx_input ON hotels.trx_id = trx_input.id
WHERE hotels.country = 'DE' AND children_type != 2
ORDER BY hotels.hotel
LIMIT 1000
But count_children is always NULL. If I replace children_ids with some real values, it works:
SELECT hotels.id,
hotels.hotel,
hotels.country,
hotels.corrected,
hotels.children_type,
hotels.children_ids as children_ids,
(SELECT SUM(trx_input.count) FROM hotels LEFT JOIN trx_input ON hotels.trx_id = trx_input.id WHERE hotels.id IN (338666,338665,338456,338691)) as count_children,
trx_input.count
FROM hotels
LEFT JOIN trx_input ON hotels.trx_id = trx_input.id
WHERE hotels.country = 'DE' AND children_type != 2
ORDER BY hotels.hotel
LIMIT 1000
Is there any way to use the value of an outer column inside a subquery?
You can do what you want using find_in_set():
(SELECT SUM(i.count)
FROM hotels h2 JOIN
trx_input i
ON h2.trx_id = i.id
WHERE find_in_set(h2.id, h.children_ids) > 0
) as count_children,
However, you should fix your data structure to use a proper junction table. Storing lists of ids in a comma delimited column is not the right way to store data.
You can replace In (children_ids) by In ( select children_ids from hotels hotls1 where hotels.id = hotels1.I'd)
So my database is composed of 5 tables with different columns for each one. The only column that keeps them all identified is the id. I'm trying to get the data for a specific user, but I only seem to get all users of the database instead.
This is what I have tried:
SELECT
ControlAccess.UserName,
ControlAccess.Pass,
Users.First_Name,
Users.Last_Name,
UserInfo.Age,
UserInfo.Country,
UserInfo.Address,
UserInfo.ZipCode,
Sessions.Matrix1,
Sessions.Matrix2,
Sessions.Result,
Operations.Operation,
FilePath.LocationFiles
FROM
MatrixUsers.UserInfo
INNER JOIN
MatrixUsers.Users
ON
UserInfo.idUserInfo = Users.idUsers = 1
INNER JOIN
MatrixUsers.ControlAccess
ON
ControlAccess.idControlAccess = UserInfo.idUserInfo = 1
INNER JOIN
MatrixUsers.Sessions
ON
Sessions.idSessions = ControlAccess.idControlAccess = 1
INNER JOIN
MatrixUsers.FilePath
ON
FilePath.idFilePath = Sessions.idSessions = 1
INNER JOIN
MatrixUsers.Operations
ON
Operations.idOperations = FilePath.idFilePath = 1;
I tried putting 1 at the end of each id to see if they matched, but I still get all the users.
I'm new to SQL and I'm only familiar with matching rows, but not choosing specific one.
Here are the columns of each table:
ControlAccess: {idControlAccess, UserName, Pass}
Sessions: {idSessions, Matrix1, Matrix2, Result}
FilePath: {idFilePath, LocationFiles}
Operations: {idOperation, Operation}
UserInfo: {idUserInfo, Age, Country, Address, ZipCode, Phone}
Use WHERE when you want specific user. for example, select user_id from table where user_id=the_specific_user_id . Follow this basic to built you complicate statement.
Just user where after all the joins
WHERE ANY_COLUMN_REFER_TO_USER_ID = YOUR_NEEDED_ID
so your full query would be like :
SELECT
ControlAccess.UserName,
ControlAccess.Pass,
Users.First_Name,
Users.Last_Name,
UserInfo.Age,
UserInfo.Country,
UserInfo.Address,
UserInfo.ZipCode,
Sessions.Matrix1,
Sessions.Matrix2,
Sessions.Result,
Operations.Operation,
FilePath.LocationFiles
FROM MatrixUsers.UserInfo
INNER JOIN MatrixUsers.Users
ON UserInfo.idUserInfo = Users.idUsers
INNER JOIN MatrixUsers.ControlAccess
ON ControlAccess.idControlAccess = UserInfo.idUserInfo
INNER JOIN MatrixUsers.Sessions
ON Sessions.idSessions = ControlAccess.idControlAccess
INNER JOIN MatrixUsers.FilePath
ON FilePath.idFilePath = Sessions.idSessions
INNER JOIN MatrixUsers.Operations
ON Operations.idOperations = FilePath.idFilePath
WHERE UserInfo.idUserInfo = 1
I'm not sure what I'm trying to do is possible but I've been trying to get different methods to a solution I need but so far I've come up empty handed.
Lets say I have 2 tables (just an example, in my case theres a hell of a lot more + alot more data)
One called clients and the other called form_data.
We have multiple clients in the clients table and in the form_data table we have multiple rows for each company present in the clients table. In form_data we store the serialized data from different forms. (id and data)
I'm currently pulling all records from the form_data table and I am trying to use a regexp on the data column to filter for instance that the value 'motor oil' is found in them.
I would like a way to do this filter but filter the company and not the forms .. so I want to find the forms that have 'motor oil' in them and the remove all entries for COMPANIES that don't have this match, but I want to keep all the forms showing for the companies that match.
I can post my query but it is rather long and i think if we can solve the above it should be sufficient for me to implement into the actual query.
Regards
EDIT:
SELECT f.form_question_has_answer_id AS f__form_question_has_answer_id, f.form_question_has_answer_request AS f__form_question_has_answer_request,
f.form_question_has_answer_form_id AS f__form_question_has_answer_form_id, f.form_question_has_answer_user_id AS f__form_question_has_answer_user_id,
p.project_company_has_user_id AS p__project_company_has_user_id, p.project_company_has_user_project_id AS p__project_company_has_user_project_id,
p.project_company_has_user_user_id AS p__project_company_has_user_user_id, c.company_id AS c__company_id, c.company_hall_no AS c__company_hall_no,
c.company_type AS c__company_type, c.company_company_name AS c__company_company_name, c.company_country AS c__company_country,
c.company_stand_number AS c__company_stand_number, c.company_image_file_1 AS c__company_image_file_1, p2.project_id AS p2__project_id,
p2.project_name AS p2__project_name, u.user_id AS u__user_id, u.user_username AS u__user_username, f2.form_id AS f2__form_id
FROM form_question_has_answer f
INNER JOIN project_company_has_user p ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2 ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2 ON p.project_company_has_user_project_id = f2.form_project_id
WHERE f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom" AND p.project_company_has_user_garbage_collection = 0 AND p.project_company_has_user_project_id = 29) AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
The query is from a doctrine query.
EDIT:
If i have a company with 10 forms in the form_data table if i filter by 'motor oil' all forms for that company that don't have motor oil are removed.. so if only 1 of the 10 forms for company id 144 has the word motor oil then the other 9 forms are lost in the query.. I want to keep them. What I want is any company that didn't find any forms with that match (motor oil) to have all their forms removed from the search.
All form data for all customers who have at least one form that matches the search:
SELECT * FROM `form_data`
WHERE `clientid` IN (
SELECT DISTINCT `clientid` FROM `form_data`
WHERE `data` RLIKE '[[:<:]]motor oil[[:>:]]'
);
SELECT
c.*
FROM
clients as c
INNER JOIN (
select
*
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
http://sqlfiddle.com/#!3/5b616/1
in this part:
select
*
from
forms
where
sometext like '%motor oil%'
you can put any query that selects the relevant rows from your forms table with the appropriate filters.
you can do the inverse too with a left outer join where null technique.. though in this case modifying the subquery to return a list of distinct clients will probably give you more like the results you expect:
SELECT
c.*
FROM
clients as c
LEFT OUTER JOIN (
select
distinct
client
from
forms
where
sometext like '%motor oil%'
) as f
ON f.client = c.id
where f.client is null
http://sqlfiddle.com/#!3/5b616/4
so with your query something like:
SELECT
c.*
FROM
company AS c
INNER JOIN (
SELECT
DISTINCT c.company_id
FROM
form_question_has_answer f
INNER JOIN project_company_has_user p
ON f.form_question_has_answer_user_id = p.project_company_has_user_user_id
INNER JOIN company c
ON p.project_company_has_user_company_id = c.company_id
INNER JOIN project p2
ON p.project_company_has_user_project_id = p2.project_id
INNER JOIN user u
ON p.project_company_has_user_user_id = u.user_id
INNER JOIN form f2
ON p.project_company_has_user_project_id = f2.form_project_id
WHERE
f.form_question_has_answer_id IN ('19262', '21560', '23088', '22660', '14772', '18495', '18720', '21625', '19957', '20943')
AND ((f2.form_template_name = "custom"
AND p.project_company_has_user_garbage_collection = 0
AND p.project_company_has_user_project_id = 29)
AND f.form_question_has_answer_request REGEXP 'item-cadcae')
ORDER BY company_company_name asc
) as f
ON f.company_id= c.id
Not sure What do you mean by keeping all the forms showing for the companies that match?
Aren't just getting at this...
select * from clients inner join form_data on clients.id = form_data.id where form_data.[data] like '%motor oil%'
This will return all forms with 'motor oil' in them filled for the companies which also have 'motor oil' in their name:
SELECT *
FROM clients c
JOIN form_data fd
ON fd.client = c.id
WHERE fd.data RLIKE '[[:<:]]motor oil[[:>:]]'
AND c.name RLIKE '[[:<:]]motor oil[[:>:]]'