SQL query one table multiple choices - mysql

I need help for designing an SQL statement. It will be created on the fly in a Web Server back end, depending on the request. This will filter a database for the desired results.
To describe my need in simplest form:
One table, two fields, 50 staff, 30 skills.
Example:
staff_id, skill_id
1, 1
1, 2
1, 3
1, 4
2, 2
2, 3
2, 4
3, 2
4, 3
Q: Who has Skill 3
A: Staff 1,2,4
(This is easy)
Q: Who has Skill 2 AND 3
A: Staff 1,2
The actual query will have a request for 5 or 6 Skills

Considering that the number of skills varies from time to time, the best way to handle this via temp table..Here is the pseudocode...syntax needs to be fixed.
create procedure my_procedure(string of skillsets)
begin
create table #tmp_skillsets(skillset smallint)
foreach skillset in skillsets
insert into #tmp_skillsets(convert_to_smallint(skillset))
select distinct staff from myTable, #tmp_skillset
where myTable.skillset = #tmp_skillsets
end
Call this procedure like: "exec my_procedure("1456") or "exec my_procedure("179248503")

I think this should work:
SELECT DISTINCT staff_id
FROM oneTable t
WHERE EXISTS (SELECT 1 FROM oneTable ti WHERE t.staff_id = ti.staff_id AND ti.skill_id = 2)
AND EXISTS (SELECT 1 FROM oneTable ti WHERE t.staff_id = ti.staff_id AND ti.skill_id = 3)

Related

Mysql query not return correctly

I am having problem with these result. I have been trying but no luck.
jobs table
id, title ... all details
1, title1,...
2, title2,...
3, title3,...
4, title4,...
job_user table
id,id_job,id_user
1,1,1
2,2,3
3,3,3
4,4,4
following_job table
id,id_job,id_user
1, 1, 3
So basically, user 3 has 2 jobs (2,3), and he follows job 1 of user 1. so, if i login as user 3, i would like to get all details jobs of user <> 3 (just the requirement that i need to do). i would get the result
id,id_job,id_user
1,1,1
4,4,4
My goal results would be :
id,title..., following_id
1,title1,...,1
4,title4,...,0
the following_id will be added as result above, since user 3 followed id_job 1 so its following_id = 1 else = 0. And id_job 1,4 will joined with jobs table to get details about it : title ...
I am doing the follow/unfollow job functionality
Thanks all
So... it seems like you want something like:
SELECT
jobs.id,
jobs.title,
jobs....,
CASE WHEN following_job.id_user = 3 THEN 1 ELSE 0 END as following_job
FROM
jobs
INNER JOIN job_user ON job.id = job_user.id_job
LEFT OUTER JOIN JOIN following_job on job.id = following_job.id_job
WHERE
job_user.id_user <> 3;
Joining all three tables according to your schema. Filtering via the WHERE clause to insure that no jobs that are no jobs that user 3 has. And then a CASE (or IF()) statement to flag the job as followed by user 3.

Mysql Dynamic crosstab Pivot comparison on one table

I have a many to many table setup. This is an example of table I am focusing on.
many_to_many_id, foreign_key_id
1, 1
1, 2
1, 3
2, 1
2, 2
3, 1
3, 4
I need to given many_to_many_id 1 find any other many_to_many_ids that have matching foreign keys that exist within the first set. Given the first set 1, 2, 3 attached to many_to_many_id would return 2 as 1, and 2 are inside the set, but 3 would not be returned as 4 is not part of the test set. My boss has said I should use a dynamic cross tab to create two tables to compare with a join. I have looked for examples but they have not been helpful.
You can do this with a few simple sub-queries. The first will make sure that for each many_to_many_id there is at least one foreign_key_id in the set you're looking for (1, 2, 3) and the second will make sure there isn't even one foreign_key_id not in the set you're looking for.
SET #search_id = 1;
SELECT m.many_to_many_id FROM SampleTable m
WHERE m.many_to_many_id != #search_id
AND EXISTS ( SELECT 1 FROM SampleTable a WHERE a.many_to_many_id = m.many_to_many_id AND a.foreign_key_id IN ( SELECT b.foreign_key_id FROM SampleTable b WHERE b.many_to_many_id = #search_id ) )
AND NOT EXISTS ( SELECT 1 FROM SampleTable a WHERE a.many_to_many_id = m.many_to_many_id AND a.foreign_key_id NOT IN ( SELECT b.foreign_key_id FROM SampleTable b WHERE b.many_to_many_id = #search_id ) )
GROUP BY m.many_to_many_id
SQL Fiddle Here

searching for records in mysql using or - and - not in query

I think I am getting turned around when looking at this. I am trying to get all patron records relating to transactions that have a transaction item with one of a number of ids (1 or 2) as well as transaction items with other ids (3 or 4) but not with transaction items with other ids (5 or 6)
The structure is:
=patron=
id
fname
lname
email
phone
=trans=
id
id_org
id_patron
=trans_item=
id
id_trans
id_perf
I was trying the following:
SELECT
patron.email,
patron.fname,
patron.lname,
patron.phone
FROM
trans_item,
trans,
patron
WHERE
trans_item.id_perf IN (1,2)
AND
trans_item.id_perf IN (3,4)
AND
trans_item.id_perf NOT IN (5,6)
AND
trans_item.id_trans = trans.id
AND
trans.id_org = 1
AND
trans.id_patron = patron.id
GROUP BY
patron.id
ORDER BY
patron.email DESC,
patron.phone DESC
I'm aware that saying the id needs to be 2 AND 4 is always going to return nothing but I need to have it as if id is in (1,2) AND (3,4) so it can be 1 or 2 but also needs to be in 3 or 4
For Clarity:
I am trying to get patrons who have gone to performance 1 OR 2 and 3 OR 4 but NOT 5 OR 6
You can do this with group by and having. The basic idea is:
select ti.id_trans
from trans_item ti
group by ti.id_trans
having sum(ti.id_perf in (1, 2)) > 0 and
sum(ti.id_perf in (3, 4)) > 0 and
sum(ti.id_perf in (5, 6)) = 0;
Each condition in the having clause checks a row for the particular ids. The > 0 means they exist for transaction. The = 0 means they do not.
If you want additional columns from other tables, you can join back to this result set.
I think I have a solution. If I combine the ids for all perfs and group all results by the trans_item.id I can get a list that has duplicates. I then convert them into a php multidimensional array and exclude / include based on the ids for each requirement finding the duplicates that way. Any other suggestions are welcome

How to do this query against MySQL database table?

I was given a task to show the CPU usage trend as part of a building process which also do regression test.
Each individual test case run has a record in the table RegrCaseResult. The RegrCaseResult table looks something like this:
id projectName ProjectType returnCode startTime endTime totalMetrics
1 'first' 'someType' 16 'someTime' 'someOtherTime' 222
The RegrCaseResult.totalMetrics is a special key which links to another table called ThreadMetrics through ThreadMetrics.id.
Here is how ThreadMetrics will look like:
id componentType componentName cpuTime linkId
1 'Job Totals' 'Job Totals' 'totalTime' 34223
2 'parser1' 'parser1' 'time1' null
3 'parser2' 'generator1' 'time2' null
4 'generator1' 'generator1' 'time3' null
------------------------------------------------------
5 'Job Totals' 'Jot Totals' 'totalTime' 9899
...
The rows with the compnentName 'Job Totals' is what the totalMetrics from RegrCaseResult table will link to and the 'totalTime' is what I am really want to get given a certain projectType. The 'Job Totals' is actually a summation of the other records - in the above example, the summation of time1 through time3. The linkId at the end of table ThreadMetrics can link back to RegrCaseResult.id.
The requirements also states I should have a way to enforce the condition which only includes those projects which have a consistent return code during certain period. That's where my initial question comes from as follows:
I created the following simple table to show what I am trying to achieve:
id projectName returnCode
1 'first' 16
2 'second' 16
3 'third' 8
4 'first' 16
5 'second' 8
6 'first' 16
Basically I want to get all the projects which have a consistent returnCode no matter what the returnCode values are. In the above sample, I should only get one project which is "first". I think this would be simple but I am bad when it comes to database. Any help would be great.
I tried my best to make it clear. Hope I have achieved my goal.
Here is an easy way:
select projectname
from table t
group by projectname
having min(returncode) = max(returncode);
If the min() and max() values are the same, then all the values are the same (unless you have NULL values).
EDIT:
To keep 'third' out, you need some other rule, such as having more than one return code. So, you can do this:
select projectname
from table t
group by projectname
having min(returncode) = max(returncode) and count(*) > 1;
select projectName from projects
group by projectName having count(distinct(returnCode)) = 1)
This would also return projects which has only one entry.
How do you want to handle them?
Working example: http://www.sqlfiddle.com/#!2/e7338/8
This should do it:
SELECT COUNT(ProjectName) AS numCount, ProjectName FROM (
SELECT ProjectName FROM Foo
GROUP BY ProjectName, ReturnCode
) AS Inside
GROUP BY Inside.ProjectName
HAVING numCount = 1
This groups all the ProjectNames by their names and return codes, then selects those that only have a single return code listed.
SQLFiddle Link: http://sqlfiddle.com/#!2/c52b6/11/0
You can try something like this with Not Exists:
Select Distinct ProjectName
From Table A
Where Not Exists
(
Select 1
From Table B
Where B.ProjectName = A.ProjectName
And B.ReturnCode <> A.ReturnCode
)
I'm not sure exactly what you're selecting, so you can change the Select statement to what you need.

Complex - returning information that is not found in the database

I have a strange query to perform from a website. I have sets of arrays that contain pertinent ids from a many tables - 1 table per array. For example (the array name is the name of the table):
Array Set 1:
array "q": 1,2,3
array "u": 1,5
array "k": 7
Array Set 2:
array "t": 2,12
array "o": 8, 25
Array Set 3 (not really a set):
array "e": 5
I have another table, Alignment, which is not represented by the arrays. It performs a one to many relationship, allowing records from tables q,u, and k (array set 1, and recorded as relType/relID in the table) to be linked to records from t and o (array set 2, recorded as keyType/keyID) and e (array set 3, recorded as keyType/keyID). Example below:
Table: Alignment
id keyType keyID relType relID
1 e 5 q 1
2 o 8 q 1
3 o 8 u 1
4 t 2 q 2
5 t 2 k 7
6 t 12 q 1
So, in record 6, a record with an id of 12 from table t is being linked to a record with an id of 1 from table q.
I have to find missing links. The ideal state is that each of the ids from array set 1 have a record in the alignment table linking them to at least 1 record from array set 2. In the example, alignment record 1 does not count towards this goal, because it aligns a set 1 id to a set 3 id (instead of set 2).
Scanning the table, you can quickly see that there are some missing ids from array set 1: "q"-3 and "u"-5.
I've been doing this with script, by looping through each set 1 array and looking for a corresponding record, which generates a whole bunch of sql calls and really kills any page that calls this function.
Is there some way I could accomplish this in a single sql statement?
What would I like the results to look like (ideally):
recordset (consisting magically of data that didn't exist in the table):
relType | relID
q 3
u 5
However, I would be elated with even a binary type answer from the database - were all the proper ids found: true or false? (Though the missing records array is required for other functions, but at least I'd be able to choose between the fast and slow options).
Oh, MySQL 5.1.
User Damp gave me an excellent answer using a temporary table, a join, and an IS NULL statement. But it was before I added in the wrinkle that there was a third array set that needed to be excluded from the results, which also ruins the IS NULL part. I edited his sql statement to look like this:
SELECT *
FROM k2
LEFT JOIN alignment
USING ( relType, relID )
HAVING alignment.keyType IS NULL
OR alignment.keyType = "e"
I've also tried it with a Group By relID (i always thought that was a requirement of the HAVING clause). The problem is that my result set includes "q"-1, which is linked to all three types of records ("o","t", and "e"). I need this result excluded, but I'm not sure how.
Here's the sql I ended up with:
SELECT *
FROM k2
LEFT JOIN (
SELECT *
FROM alignment
WHERE keyType != 'e' and
(
(relType = 'q' AND relID IN ( 1, 2, 3 ))
OR
(relType = 'u' AND relID IN ( 1, 5 ))
OR
(relType = 'k' AND relID IN ( 7 ))
)
)A
USING ( relType, relID )
HAVING keyType Is Null
I have to dump the values for the IN qualifiers with script. The key was not to join to the alignment table directly.
You can try to go this route:
DROP TABLE IF EXISTS k2;
CREATE TEMPORARY TABLE k2 (relType varchar(10),relId int);
INSERT INTO k2 VALUES
('q',1),
('q',2),
('q',3),
('u',1),
('u',5),
('k',7);
SELECT * FROM k2
LEFT JOIN Alignment USING(relType,relId)
HAVING Alignment.keyType IS NULL
This should work well for small tables. Not sure about very large ones though...
EDIT
If you wanted to add a WHERE statement the query would be as follow
SELECT * FROM k2
LEFT JOIN Alignment USING(relType,relId)
WHERE Alignment.keyType != 'e'
HAVING Alignment.keyType IS NULL