I have this MySQL table posts:
id | content | parentid | userid
--------------------------------------
01 | Post test #1 | 0 | 1
02 | Post test #2 | 0 | 1
03 | Comment #1 | 1 | 2
04 | Comment #2 | 1 | 1
05 | Post test #3 | 0 | 3
06 | Comment #3 | 1 | 2
07 | Comment #4 | 2 | 5
08 | Comment #5 | 5 | 6
09 | Comment #6 | 1 | 4
10 | Post test #4 | 0 | 4
This is just an example for stackoverflow
Now I need to LIMIT comments for each post and so far I have used this query:
SELECT
`posts`.`id` AS `post_id`,
`posts`.`content` AS `post_content`,
`posts`.`parentid` AS `post_parentid`,
`posts`.`userid` AS `post_userid,
`comments`.`id`, 0 AS `comment_id`,
`comments`.`content` AS `comment_content`,
`comments`.`parentid` AS `comment_parentid`,
`comments`.`userid` AS `comment_userid,
IF( IFNULL( `comments`.`id`, 0 ) > 0, "comment", "post" ) AS `contenttype`
FROM `posts` AS `posts`
LEFT JOIN ( SELECT "" AS `hello` ) AS `useless` ON #pid := `posts`.`id`
LEFT JOIN ( SELECT
`posts`.`id` AS `id`,
`posts`.`id` AS `id`,
`posts`.`id` AS `id`,
`posts`.`id` AS `id`
FROM `posts`
WHERE `posts`.`parentid` = #pid
LIMIT 10
) AS `comments`ON `comments`.`parentid` = `posts`.`id`
WHERE
`posts`.`userid` = {USERID}
To archive this I have joined an useless "table" just to update #pid (parentid) variable.
Is this the only way to LIMIT subquery results? I don't like the idea of that useless JOIN.
What if I have to LIMIT posts in the example above without affecting the comments LIMIT. Can you please give me a better query?
The real reason of posting this question was to load 10 comments with 10 sub-comments for each comment. On the question I have asked to load posts & comments so the idea is the same.
The example posted in my question doesn't works because the subquery will executed before the variable #pid gets updated.
Because I'm using PHP then I'm posting here the solution in MySQL & PHP for this situation.
1 - First let's load posts with this SQL query
SELECT
`posts`.`id` AS `id`,
`posts`.`content` AS `content`,
`posts`.`parentid` AS `parentid`,
`posts`.`userid` AS `userid
FROM `posts` AS `posts`
WHERE
`posts`.`userid` = {USERID}
AND
`posts`.`parentid` = '0'
ORDER BY `posts`.`id` DESC
LIMIT 10
2 - Store posts information in $posts array:
$posts = [];
while ( $row = $result->fetch_object() )
{
$posts[] = (object) [ "id" => $row->id,
"content" => $row->content,
"userid" => $row->userid,
"comments" => []
];
}
3 - Prepare SQL to load comments:
$size = count( $posts );
$sql = "";
for ( $i = 0; $i < $size; $i ++ )
{
$sql .= ( $sql != "" ? "UNION ALL " : "" )
. "( "
. "SELECT "
. "`comments`.`id` AS `id`, "
. "`comments`.`content` AS `content`, "
. "`comments`.`parentid` AS `parentid`, "
. "`comments`.`userid` AS `userid "
. "FROM `posts` AS `comments` "
. "WHERE "
. "`comments`.`parentid` = '" . $post[ $i ]->id . "' "
. "ORDER BY `comments`.`id` ASC "
. "LIMIT 10 "
. ") ";
}
4 - After executing the $sql code let's store comments for each post:
while ( $row = $result->fetch_object() )
{
$posts[ $row->parentid ]->comments[] = (object)[
"id" => $row->id,
"content" => $row->content,
"userid" => $row->userid,
];
}
As you can see this can be used for also comments (instead of posts ) & sub-comments (instead of comments). MySQL variables are not helpful this time. Of course to create a pagination you have to add additional field (replies) in the table and update that during comment creation.
If someone has a better solution is welcomed.
I have an SQL query that produces team standings based off the old NHL format. The first section of the code gets the top 3 teams in each division, and the 2nd bit gets the rest and sorts them by points/differential.
This can be seen here: http://rgmgstandings.tk
Here is my SQL query:
("(SELECT *, 1 as `SortKey` from `standings_east`
WHERE pts = (select max(pts)
from standings_east as t
where t.`div` = standings_east.`div`))
UNION ALL
(select *, 2 as SortKey from `standings_east`
where team not in
(select team from standings_east
where pts = (select max(pts)
from standings_east as t
where t.`div` = standings_east.`div`)))
order by SortKey, pts desc, diff desc")
If you visit my website, and look at the standings for the Western Conference (blue banner), you will notice 3 teams in 'CEN' that have the same amount of points (Chicago, Winnipeg, Columbus)
I want the query to select only ONE team from that division based on whoever has the most 'Wins/W'.
The correct standings should be:
Edmonton (NW) 80
Anaheim (PAC) 74
Columbus (CEN) 71
Dallas (PAC) 73
Chicago (CEN) 71
Winnipeg (CEN) 71
How can I accomplish this?
Query
select team,`div`,pts,1 as sortOrder
from
( -- note use parentheses to avoid mysql error 1221
(select team,`div`,pts,#cen:=team from `standings_west` where `div`='CEN' order by pts desc limit 1)
union all
(select team,`div`,pts,#pac:=team from `standings_west` where `div`='PAC' order by pts desc limit 1)
union all
(select team,`div`,pts,#nw:=team from `standings_west` where `div`='NW' order by pts desc limit 1)
) xDerived1
cross join (select #cen='',#pac='',#nw='') params
union
select team,`div`,pts,sortOrder
from
( select team,`div`,pts,2 as sortOrder
from `standings_west`
where team!=#cen and team!=#pac and team!=#nw
order by pts desc
limit 3
) xDerived2
order by sortOrder,pts desc;
Results
+----------+-----+-----+-----------+
| team | div | pts | sortOrder |
+----------+-----+-----+-----------+
| EDMONTON | NW | 80 | 1 |
| ANAHEIM | PAC | 74 | 1 |
| WINNIPEG | CEN | 71 | 1 |
| DALLAS | PAC | 73 | 2 |
| CHICAGO | CEN | 71 | 2 |
| COLUMBUS | CEN | 71 | 2 |
+----------+-----+-----+-----------+
Stored Proc
The following depicts a stored proc just to show it in case you are having problems and need it.
drop procedure if exists xdoit;
delimiter $$
create procedure xdoit()
begin
select team,`div`,pts,1 as sortOrder
from
( -- note use parentheses to avoid mysql error 1221
(select team,`div`,pts,#cen:=team from `standings_west` where `div`='CEN' order by pts desc limit 1)
union all
(select team,`div`,pts,#pac:=team from `standings_west` where `div`='PAC' order by pts desc limit 1)
union all
(select team,`div`,pts,#nw:=team from `standings_west` where `div`='NW' order by pts desc limit 1)
) xDerived1
cross join (select #cen='',#pac='',#nw='') params
union
select team,`div`,pts,sortOrder
from
( select team,`div`,pts,2 as sortOrder
from `standings_west`
where team!=#cen and team!=#pac and team!=#nw
order by pts desc
limit 3
) xDerived2
order by sortOrder,pts desc;
end$$
delimiter ;
call stored proc
call xdoit();
A few comments here.
First, your sqlfiddle had data from the west, but a query from the east. Based on table names, I suggest you have all your data in one table not two and have a column for east or west.
The query uses a cross join to merely establish variables for grabbing the division leaders so those division leaders are excluded for the sortOrder=2 teams.
Tweak as necessary for tie-breaks (ie: the teams with 71 points) regarding your implemention of DIFF in comments to #Clockwork
Ask if you have any questions.
The following is the multi_query php solution I came up with for you based on your posting of a comment in that chat room.
The only solution I could come up with was the following based on clearly the results were coming back in two result sets. Thus the while loop that is driven by next_result(). The first result set has the top 3 rows, the 2nd result set has the twelve rows that follow. That is just the way PHP seems to see it.
Also note that in the PHP part, since I seemed to be dealing with a multi_query, I took advantage of that and passed the mysql parameters in versus doing a cross join to pick them up.
PHP
<!DOCTYPE html>
<html lang="en">
<head>
<title>RGMG: Standings</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</head>
<body>
<?php
//mysqli_report(MYSQLI_REPORT_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
error_reporting(E_ALL); // report all PHP errors
ini_set("display_errors", 1);
try {
$mysqli= new mysqli('localhost', 'dbUser', 'thePassword', 'theDbName');
echo "<table><div><br><br>"; // note you had this line a little bit wrong
// notice below the concat of the $sql and the multi_query()
$sql = "set #cen:='',#pac:='',#nw:=''; ";
$sql .= "select *
from
( select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,1 as sortOrder
from
( -- note use parentheses to avoid mysql error 1221
(select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,#cen:=team from `standings_west` where `div`='CEN' order by pts desc, win desc, diff desc limit 1)
union all
(select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,#pac:=team from `standings_west` where `div`='PAC' order by pts desc, win desc, diff desc limit 1)
union all
(select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,#nw:=team from `standings_west` where `div`='NW' order by pts desc, win desc, diff desc limit 1)
) xDerived1
union all
select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,sortOrder
from
( select team,`div`,gp,win,lose,otl,goalsF,goalsA,diff,gpg,gaa,pts,2 as sortOrder
from `standings_west`
where team!=#cen and team!=#pac and team!=#nw
order by pts desc
) xDerived2
) xDerived3
order by sortOrder,pts desc";
echo "<div class='container'>";
echo "<img src='http://i.imgur.com/sjDHhIV.png' width='100%' alt='West'>";
echo "<table class='table table-condensed'>
<tr class='top'>
<th class='rank'></th>
<th class='team'>TEAM</th>
<th>DIV</th>
<th>GP</th>
<th>W</th>
<th>L</th>
<th class='otl'>OTL</th>
<th class='pts'>PTS</th>
<th>GF</th>
<th>GA</th>
<th>DIFF</th>
<th>GPG</th>
<th>GAA</th>
";
$counter=1;
$mysqli->multi_query($sql);
while(true) {
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_assoc()) {
$gpg = ($row['goalsF']);
$gaa = ($row['goalsA']);
if ($row['gp'] != 0 ){
$gpg = ($row['goalsF'] / $row['gp']);
$gaa = ($row['goalsA'] / $row['gp']);
}
else {
$row['gp'] = "";
}
echo "<tr>
<td class='rank'>" . "$counter" . "</td>
<td class='team'>" . $row['team'] . "</td>
<td>" . $row['div'] . "</td>
<td>" . $row['gp'] . "</td>
<td>" . $row['win'] . "</td>
<td>" . $row['lose'] . "</td>
<td class='otl'>" . $row['otl'] . "</td>
<td class='pts'>" . $row['pts'] . "</td>
<td>" . $row['goalsF'] . "</td>
<td>" . $row['goalsA'] . "</td>
<td>" . $row['diff'] . "</td>
<td>" . round($gpg, 2) . "</td>
<td>" . round($gaa, 2) . "</td>";
$counter++;
}
$result->free();
}
if ($mysqli->more_results()) {
$mysqli->next_result();
}
else {
break;
}
}
echo "</table></div>";
$mysqli->close();
} catch (mysqli_sql_exception $e) {
throw $e;
}
?>
</body>
</html>
First i love NHL and from your query we can say the table you are showing us is standings_east,so let's try this:
select team,DIV,GP,W,L,OTL,PTS,GF,GA,DIFF,GPG,GAA,1 as sort_key
from standings_east t
where exists
(select 1
from
(select DIV,max(PTS) as PTS,max(W) as W from standings_east
group by DIV) a
where t.DIV=a.DIV and t.PTS=a.PTS and t.W=a.W
)
UNION ALL
select team,DIV,GP,W,L,OTL,PTS,GF,GA,DIFF,GPG,GAA,2 as sort_key
from standings_east t
where not exists
(select 1
from
(select DIV,max(PTS) as PTS,max(W) as W from standings_east
group by DIV) a
where t.DIV=a.DIV and t.PTS=a.PTS and t.W=a.W
)
order by sort_key,PTS DESC
i think there is some better way but this is the one like yours the most and the easiest to understand just add a group by on your code and Merry Christmas
I have two tables user and work. Work table has multiple user's work experience.I have to retrieve most recent 2 companies on the basis of start date.
Conditions :
1.If Work Table has multiple user's Id's records, retrieve recent 2 records and show in single row (e.g. User_id = 1)
2.If Work Table has single record is most recent companies record and second record should be "NULL"(e.g. user_id = 3).
user
user_id First_name Last_name
1 AAA BBB
2 PPP QQQ
3 SSS RRR
work
user_id recent_company position start_year end_year
1 ABC CCC 2014 2015
1 PQR DDD 2013 2014
1 MNO EEE 2012 2013
1 MNO EEE 0000 0000
2 XYZ TTT 2008 2009
2 IJK MMM 2005 2008
3 QRS ZZZ 2001 2002
I've tried for most recent company record 1 :
select u.user_id,u.first_name,u.last_name,uw.recent_company1,uw.position1,uw.start_year,uw.end_year from muser u
left join
(SELECT user_id,recent_company,position,MAX(start_year) as start_year,end_year
FROM work
group by user_id
order by user_id) uw ON u.user_id =uw.user_id
Result of my query for 1st recent company on start year basis:
user_id First_name Last_name recent_company1
1 AAA BBB ABC
2 PPP QQQ XYZ
3 SSS RRR QRS
position1 start_year1 end_year1
CCC 2014 2015
TTT 2008 2009
ZZZ 2001 2002
Required Output for both 1st and 2nd recent company on start_year basis:
user_id First_name Last_name recent_company1 position1
1 AAA BBB ABC CCC
2 PPP QQQ XYZ TTT
3 SSS RRR QRS ZZZ
start_year1 end_year1
2014 2015
2008 2009
2001 2002
recent_company2 position2 start_year2 end_year2
PQR DDD 2013 2014
IJK MMM 2005 2008
NULL NULL NULL NULL
i have done the same thing using the php script.
I am also looking for the answer using sql query .. so that it can be done within the sql query ..
function tag_listing() {
echo 'Row Number' . ',' . 'TagID' . ',' . 'Status' . ',' . 'UserName' . ',' . 'Country' . ',' . 'PostCode' . ',';
$array = array('First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth', 'Seventh', 'Eighth', 'Ninth', 'Tenth');
$entityName = "Allocation Entity";
$entity_type = "Entity Type";
$allocDate = "Allocation Date";
$sqlCount = "SELECT count(*) as total from tag_allocation group by id_tag HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC";
$countQuery = $this->db->query($sqlCount);
foreach ($countQuery->result() as $NewTotal) {
$resRows = $NewTotal->total;
$item = array_slice($array, 0, $resRows);
foreach ($item as $items) {
echo $items . ' ' . $entityName . ',';
echo $items . ' ' . $entity_type . ',';
echo $items . ' ' . $allocDate . ',';
}
break;
}
$query = $this->db->query("select id_tag_id, IT.id_tag, ITS.status,
CASE WHEN firstname IS NULL THEN '' ELSE CONCAT(firstname,' ',lastname) END as Username,
CASE WHEN U.country IS NULL THEN '' ELSE U.country END as Country,
CASE WHEN U.postcode IS NULL THEN '' ELSE U.postcode END as postcode,
CASE WHEN E.entity_name IS NULL THEN '' ELSE E.entity_name END as entity_name,
ET.entity_type, TA.allocation_date, TA.allocation_type from id_tag IT
INNER JOIN id_tag_status ITS ON IT.id_tag_status_id = ITS.id_tag_status_id
RIGHT JOIN tag_allocation TA ON IT.id_tag = TA.id_tag
INNER JOIN entity_type ET ON ET.entity_type_id = TA.allocation_type
LEFT JOIN allocation_entity E ON E.entity_id = TA.entity_id
LEFT JOIN user U ON U.user_id = IT.user_id
order by IT.id_tag, TA.allocation_date asc ");
$IDTAG = '';
$rowCount = 0;
foreach ($query->result() as $row) {
$newID = $row->id_tag;
if ($IDTAG != $newID) {
echo "\r\n";
}
if ($IDTAG == $newID) {
echo $entityName = $row->entity_name . ',' . $entityType = $row->entity_type . ',' . $allocationDate = $row->allocation_date . ',';
} else {
$rowCount = $rowCount + 1;
$IDTAG = $row->id_tag;
echo $rowCount . ',' . $idTag = $row->id_tag . ',' . $status = $row->status . ',' . $Username = $row->Username . ',' . $Country = $row->Country . ',' . $postcode = $row->postcode . ',' . $entityName = $row->entity_name . ',' . $entityType = $row->entity_type . ',' . $allocationDate = $row->allocation_date . ',';
}
}
exit();
}
Hope it helps .. try this and you will get it ..
Thank you ...
I am having some problems trying to find the members with the most referrals.. I have been looking up stuff and trying stuff for more than 3 hours so this is my last resort. My goal is to list the members username and the amount of referrals they have..
So each members referral is marked by their id..
so in the example test2 is orig's ref. So each persons ref is marked by their id.
id | username | ref
1 | orig |0 (for none)
2 | test2 |1 (orig id)
3 | another |1 (orig id)
and the goal is to echo this out. If it is even possible.
UserName | Refs
test 1
test2 0
my attempt. It gives me the amount but it does not order them and echoes to many.
$result = mysql_query("SELECT * FROM members");
echo '<table class="table table-bordered"><tr><th>Credits</th><th>Username</th></tr>';
while($row = mysql_fetch_array($result))
{
$contest_id = $row['id'];
$result1 = mysql_query("SELECT COUNT(*) FROM members WHERE ref=".$row['id']."");
while($row1=mysql_fetch_array($result1))
{
$result_c = mysql_query("SELECT * FROM members ORDER BY ".$row1['COUNT(*)']."+0 DESC Limit 10");
while($row_c = mysql_fetch_array($result_c))
{
$top_id = $row_c['id'];
$find_c = mysql_query("select count(*) from members where user_id='$top_id'");
$found_c = mysql_result($find_c,0);
echo '<tr><td>';
echo $found_c;
echo '</td>';
echo '<td>';
echo $row_c['username'];
echo '</td>';
echo '</tr>';
}}}
echo '</table>';
If I understood your table lay-out correctly, this should do the trick.
SELECT t1.username, t2.numref
FROM members t1
LEFT JOIN (SELECT ref, COUNT(ref) as numref
FROM members
GROUP BY ref) t2
ON t2.ref = t1.id
ORDER BY numref DESC
It should provide a NULL value in the numref column for the users that haven't made any referrals.
For reference, I added a SQL-Fiddle!
I have a table like below :
node_name id term_name
----------------------------------------------
test1 001 physics
test1 001 maths
test1 001 chemistry
test2 002 physics
test2 002 maths
Given a combination of term names I want to find all rows where the id set only contains exactly the given term names.
For example given the term names physics & maths my output should be like below
node_name id term_name
----------------------------------------------
test2 002 physics
test2 002 maths
Id set 001 contains also chemistry that is why it should not be included.
Your question: get all rows where no other rows with same id but other term_names exists
SELECT * FROM <table> x WHERE
term_name IN ('physics','maths') AND
NOT EXISTS (SELECT * FROM <table> WHERE id=x.id AND term_name NOT IN ('physics','maths'))
first of all you need to parse your query to convert the '&' to SQL 'OR' operator
in PHP :
//Parse the query
$arr = explode('&',$query);
$where = '';
//get the term count
$count = count($arr);
foreach($arr as $value){
$where .= "term_name = '" . $value . "' OR";
}
//Remove last or
$where = rtrim($where,'OR');
then :
use L
"select node_name ,count(1) as Total from my table where $where
group by node_name
having Total =" . $count
Finally :
your query must be in this format:
select x,count(1) as total from mytable where field1 = 'term1' or field1 = 'term2' having total = 2
One possible way to do this:
select id, node_name
from nodes join
(select id,
count(*)
from nodes
where node_name in ('physics','math')
group by id
having count(*) = 2 // this is set when generating the query ) as eligible_nodes
on nodes.id = eligible_nodes.id