I have table with positions
tbl_positions
id position
1 Driver
2 Lobby
3 Support
4 Constructor
and in other table i have users
tbl_workers
id name position status
1 John 2 3
2 Mike 3 2
3 Kate 2 3
4 Andy 1 0
i do request of positions
Without status I select everything with this query .
SELECT p.id, p.position, count(*) FROM tbl_positions as p
inner join tbl_workers as w on w.position=p.id
group by p.id, p.position
But now i need output same query but also considers status, status 2=booked status, 3=placed. I need output like this in single query.
Position booked placed
Driver 0 0
Lobby 0 2
Support 1 0
Constructor 0 0
I tried add WHERE tbl_workers.status IN (2) for booked and WHERE tbl_workers.status IN (3) for placed and it works in two queries, but no luck joining this into one query
Try this:
SELECT p.id,
p.position,
SUM(CASE w.Status WHEN 2 THEN 1 ELSE 0 END) AS booked,
SUM(CASE w.Status WHEN 3 THEN 1 ELSE 0 END) AS placed
FROM tbl_positions AS p LEFT JOIN tbl_workers AS w
ON w.position=p.id
GROUP BY p.id, p.position
Although you can do this with a single SQL query, it may be more straightforward to handle this using PHP.
Use your current query and add status to the GROUP BY.
SELECT p.id, p.position, w.status, count(*) FROM tbl_positions as p
inner join tbl_workers as w on w.position=p.id
group by p.id, p.position, w.status
You'll get a result set like this:
position status count
Driver 2 0
Lobby 2 0
Support 2 1
Constructor 2 0
Driver 3 0
Lobby 3 2
Support 3 0
Constructor 3 0
Use PHP to logically determine 2 = booked and 3 = placed.
Related
I have a table like this
id userid game date_t hdigit inside outside
1 user101 xy 02-09-2017 1 10
2 user101 xy 02-09-2017 1 40
3 user101 xx 02-09-2017 2 40
4 user101 xx 02-09-2017 3 90
I want display data like
id userid game date_t hdigit inside outside
1 user101 xy 02-09-2017 1 10 40
3 user101 xx 02-09-2017 2 40
4 user101 xx 02-09-2017 3 90
I have tried this
SELECT h.userid,h.game,h.date_t,h.hdigit,h.inside,htwo.outside
FROM `hadap_game` AS h JOIN hadap_game AS htwo WHERE h.userid=:user
AND htwo.userid=:uer AND h.hdigit=htwo.hdigit AND h.game=htwo.game
AND h.inside IS NOT NULL AND htwo.outside IS NOT NULL
it is printing the above thing but I want to print the row which have null values too
I think you could probably do this simply using GROUP BY?
SELECT
h.userid,
h.game,
h.date_t,
h.hdigit,
MAX(IFNULL(h.inside, htwo.inside)) AS inside,
MAX(IFNULL(h.outside, htwo.outside)) AS outside
FROM
hadap_game AS h
LEFT JOIN hadap_game AS htwo ON htwo.userid = h.userid AND htwo.hdigit = h.hdigit AND htwo.game = h.game AND htwo.id <> h.id
WHERE
h.userid = :user
GROUP BY
h.userid,
h.game,
h.date_t,
h.hdigit;
This does a few other things that you might not need/ want, but it's basically the same as your original query, other than it works when there aren't two rows per unique reference.
Assuming that there will only ever be 1 or 2 rows (so not 3 or more matching rows):-
SELECT h.userid,
h.game,
h.date_t,
h.hdigit,
COALESCE(h.inside,h2.inside) AS inside,
COALESCE(h.outside,h2.outside) AS outside
FROM `hadap_game` AS h
LEFT OUTER JOIN hadap_game AS h2
ON h.hdigit=h2.hdigit
AND h.game=h2.game
WHERE h.userid=:user
AND h2.userid=:uer
UNION
SELECT h2.userid,
h2.game,
h2.date_t,
h2.hdigit,
COALESCE(h.inside,h2.inside) AS inside,
COALESCE(h.outside,h2.outside) AS outside
FROM `hadap_game` AS h2
LEFT OUTER JOIN hadap_game AS h
ON h.hdigit=h2.hdigit
AND h.game=h2.game
WHERE h.userid=:user2
AND h2.userid=:uer2
Hi We have 3 Table of a music which is something like this in MySql :
1st Table :
the first table is for playlist table where music playlist is exist.
playlistId playlistTitle categoryId
1 hello 0
2 wow 0
3 wi-fi 0
4 awesome 0
5 sixer 1
6 four 1
7 boundary 2
2nd Table :
2nd table is for songRelation table where every playlist is associated with thier song
playlistId songId
1 4
1 3
1 43
1 57
1 98
2 56
2 67
2 90
2 78
3 98
3 78
3 89
43 90
3rd Table : the 3rd table is for song table where song detail exist
songId songTitle
4 hello
3 real hero
43 singalone
57 awesom
98 really
78 sakaka
98 shikwa
89 moha
90 hello2
67 Sneh
actually i am fetching the result something like this:
playlistId songId categoryId songTitle
1 4 0 hello
1 3 0 real hero
2 56 0 singalone
2 67 0 Sneh
3 78 0 sakaka
3 98 0 Shikwa
where the every playlistId will be with their first 2songIdand with theircategoryIdand also withsongTitle`.
but i want to count the total song with every playlistId
after getting the total song result i want will be something like this :
playlistId songId categoryId songTitle totalSong
1 4 0 hello 5
1 3 0 real hero 5
2 56 0 singalone 4
2 67 0 Sneh 4
3 78 0 sakaka 3
3 98 0 Shikwa 3
here is the jsfiddle Demo where query is without totalSong http://sqlfiddle.com/#!9/7eda7/5
What subquery will be added to get the above desired result.
To get exactly the result you asked, use this:
select p.playlistId,
s.songId,
p.categoryId,
s.songTitle,
(select count(*) from songRelation where playlistId = p.playlistId) totalSong
from playlist p
inner join songRelation r on p.playlistId = r.playlistId
inner join song s on r.songId = s.songId
Using a group by on the main query would merge the detailed song data, forcing you to run two queries: one for details (first 4 fields) and a second query, to recover the totals (last column). Using this solution, you get all detailed data and totals, the sub-query will recover the count of songs for each playlist, the way you asked.
UPDATE:
This way, suggested by rlanvin, should make the query faster, because instead on computing the subquery for each row, it gets computed only once, and then is joined to the main query. The result is the same:
select p.playlistId,
s.songId,
p.categoryId,
s.songTitle,
r1.totalSong
from playlist p
inner join songRelation r on p.playlistId = r.playlistId
inner join song s on r.songId = s.songId
inner join (SELECT playlistid, COUNT(songId) as totalSong from songRelation group by playlistid) r1 on p.playlistId = r1.playlistId
I have added this query to ur SQLFIDDLE.
SELECT p.playlistId, s.songId, p.categoryId, s.songTitle,
(select count(sr1.songId) from songRelation sr1
where sr1.playlistid=p.playlistid
group by sr1.playlistId) as total,
#r := IF (#pid = p.playlistId,
IF (#pid := p.playlistId, #r+1, #r+1),
IF (#pid := p.playlistId, 1, 1)) AS rn
FROM playlist AS p
CROSS JOIN (SELECT #r:=0, #pid:=0) AS vars
INNER JOIN songRelation AS sr ON p.playlistId = sr.playlistId
INNER JOIN song AS s ON sr.songid = s.songid
ORDER BY p.playlistId, s.songId ) AS t
WHERE t.rn <= 2
It is giving the required output. Check the Demo Here
Using Group Functions you can do this:
SELECT `playlistid`, COUNT(`songid`)
FROM `playlist`
GROUP BY `playlistid`
I'm trying to find a patient's appointments and messages count. My table records are like below 3 table patient, appointments and messages
Patient table
pid fname lname
1 john sid
2 rother ford
3 megan rough
4 louis kane
appointments table
id pid appointment_date
1 1 2015-08-04
2 2 2015-08-05
3 1 2015-08-06
4 1 2015-08-07
5 3 2015-08-07
6 2 2015-08-08
7 4 2015-08-13
8 1 2015-08-12
Messages table
id pid description message_date
1 2 join 2015-08-04
2 2 update 2015-08-05
3 3 join 2015-08-05
4 4 update 2015-08-10
5 3 test 2015-08-07
So if write query to find counts i'm getting wrong values
SELECT pd.fname,pd.lname , pd.pid, COUNT( a.id ) AS app_cnt, COUNT( m.id ) AS mes_cnt
FROM patient pd
LEFT OUTER JOIN appointments a ON a.pid = pd.pid
LEFT OUTER JOIN messages m ON m.pid = pd.pid
GROUP BY pd.pid
ORDER BY pd.pid
fname lname pid app_cnt mes_cnt
john sid 1 4 0
rother ford 2 4 4
megan rough 3 2 2
louis kane 4 1 1
Here pid 1 have 4 appointments and 0 messages, pid 2 have 2 appointments and 2 messages but getting wrong values.
Can someone please help to resolve this issue. I'm not interested in writing sub queries for this.
Functionality looks simple but I'm really facing problem for writing query.
Anymore suggestions please.
After thoroughly analysing your problem and tables, It cannot be done directly using simple query as LEFT OUTER JOIN is returning some superfluous records, that's why to filter it, you will have to use temporary table and modify the query as:
Select temp.fname, temp.lname, temp.pid, a_count, count(m.pid) as m_count from
(SELECT fname,lname,pd.pid, count(a.pid) as a_count
FROM patients pd
LEFT OUTER JOIN appointments a ON a.pid = pd.pid group by pd.pid) temp
LEFT OUTER JOIN messages m ON m.pid = temp.pid
group by temp.pid
Explanation:
It will join patients and appointments table and group them by pid so that messages from message table do not repeat for each patients.pid.
The wrong result is as a result of left outer join as it is giving wrong results for this query
SELECT *
FROM patients pd
LEFT OUTER JOIN appointments a ON a.pid = pd.pid
LEFT OUTER JOIN messages m ON m.pid = pd.pid
Since we need to limit the results of first two joins, hence temporary table is necessary.
I have those 3 tables
candidates
cdid cdname
1 Moussa
2 Moustafa
3 Haitham
positions
posid posname
1 pos1
2 pos2
3 pos3
joboffers
cdid posid salary
1 1 600
1 2 800
1 3 700
2 1 500
2 2 700
2 3 900
3 2 1000
3 3 500
I need to make a query that get the cdname with max salary for every position
the table should be like this
cdname posname salary
moussa pos1 600
haitham pos2 1000
moustafa pos3 900
I am using this query but it's not getting the correct cdid
$sql="select joboffers.cdid,joboffers.posid,Max(joboffers.salary),candidates.cdname
FROM joboffers,candidates
Where joboffers.cdid=candidates.cdid
Group by joboffers.posid";
Try this :)
SELECT sub.cdname, sub.posname, sub.salary
FROM (
SELECT * FROM joboffers jo
INNER JOIN positions ps USING (posid)
INNER JOIN candidates cd USING (cdid)
ORDER BY posid, salary DESC
) sub
GROUP BY sub.posid
I think you need to group by all non-aggregated columns, like this:
SELECT j.cdid, c.cdname, j.posid, MAX(j.salary)
FROM joboffers j
JOIN candidates c ON j.cdid = c.cdid
GROUP BY j.cdid, c.cdname, j.posid
SELECT c.cdname, p.posname, MAX(j.salary)
FROM joboffers j
INNER JOIN candidates c ON j.cdid = c.cdid
INNER JOIN positions p ON j.posid = p.posid
GROUP BY c.cdname, p.posname
enter code hereSELECT customerNumber, MAX(amount)
FROM payments
GROUP BY customerNumber
ORDER BY MAX(amount);
I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.