MySQL query keeps doing LIMIT 1 - php

This query here is supposed to SELECT * pages where the $_GET['variables'] match the conditions. The $_GET['variables'] are $page_type = type of page AND $loc = location to search. The problem is that I have it set to LIMIT 20, but it only renders one page.
function SearchByTypeLoc($page_type, $loc) {
$query = mysql_query("
SELECT
`$page_type`.title AS title,
`$page_type`.url_title AS url_title,
`$page_type`.page_type AS page_type,
`$page_type`.street AS street,
`$page_type`.city AS city,
`$page_type`.state AS state,
`$page_type`.city_state_zip AS city_state_zip,
`$page_type`.phone AS phone,
LEFT(`$page_type`.body, 100) AS body,
LEFT(`$page_type`.type, 50) AS type,
GROUP_CONCAT( i.image_loc ) AS images
FROM `$page_type`
JOIN page_images i USING( title )
WHERE
`$page_type`.page_type = '$page_type' AND
`$page_type`.city = '$loc'
ORDER BY title
LIMIT 20");
while($fetch = mysql_fetch_assoc($query)) { ...
?>
Any idea how to make it not LIMIT 1?

GROUP_CONCAT is an aggregate function,
try explicitly add a
GROUP BY `$page_type`.title

It doesn't LIMIT 1, but there is only $page_type which matches the criteria. You join on title (why not on an id?) so there must only be one $page_type with images with a matching title.
If you want to return pages which also may not have any images then you need to change the JOIN to LEFT JOIN.
The way you link pages to images is flawed. If you change the title of a page you need to remember and update the respective title in the images table. In any case this is not a proper foreign key. You should use an auto_increment id on pages.

Related

Select a fixed number of records from a particular user in a sql result

I have 2 tables - users and articles.
users:
user_id (int)
name (varchar)
articles:
article_id (int)
user_id (int)
title (varchar)
description (text)
In my application I need to display 20 RANDOM articles on a page.
My query is like this:
SELECT a.title
, a.description
, u.name
FROM articles a
JOIN users u
USING (user_id)
ORDER
BY RAND()
LIMIT 20
A user can have any number of articles in the database.
Now the problem is sometimes out of 20 results, there are like 9-10 articles from one single user.
I want those 20 records on the page to not contain more than 3 (or say 4) articles from a particular user.
Can I achieve this through SQL query. I am using PHP and MySQL.
Thanks for your help.
You could try this?
SELECT * FROM
(
SELECT B.* FROM
(
SELECT A.*, ROW_NUMBER() OVER (PARTITION BY A.USER_ID ORDER BY A.R) USER_ROW_NUMBER
FROM
(
SELECT a.title, a.description, u.name, RND() r FROM articles a
INNER JOIN users u USING (user_id)
) A
) B
WHERE B.USER_ROW_NUMBER<=4
) C
ORDER BY RAND() LIMIT 20
Mmm, intresting I don't think this is possible through a pure sql query.
My best idea would be to have an array of the articles that you'll eventually display query the database and use the standard SELECT * FROM Articles ORDER BY RAND() LIMIT 20
The go through them, making sure that you have indeed got 20 articles and no one has breached the rules of 3/4 per user.
Have another array of users to exclude, perhaps using their user id as an index and value of a count.
As you go through add them to your final array, if you find any user that hits you rule add them to the array.
Keep running the random query, excluding users and articles until you hit your desired amount.
Let me try some code (it's been a while since I did php)
$finalArray = [];
$userArray = [];
while(count($finalArray) < 20) {
$query = "SELECT * FROM Articles ";
if(count($finalArray) > 0) {
$query = $query . " WHERE articleID NOT IN(".$finalArray.")";
$query = $query . " AND userID NOT IN (".$userArray.filter(>4).")";
}
$query = $query . " ORDER BY Rand()";
$result = mysql_query($query);
foreach($row = mysql_fetch_array($result)) {
if(in_array($finalArray,$row) == false) {
$finalArray[] = $row;
}
if(in_array($userArray,$row[userId]) == false) {
$userArray[$row[userId]] = 1;
}
else {
$userArray[$row[userId]] = $userArray[$row[userId]] + 1;
}
}

Paginate while ignoring sub rows, with a Right Join

I have this basic query that returns a main row of a program title(eventdesc) and then lists program participants and info as multiple sub rows.
PROGRAM 1
Email 1, email 2, name, status (first participant)
Email 1, email 2, name, status (second participant)
PROGRAM 2
Email 1, Email 2, name, status (first participant)
ETC...
Basic query:
$query_perpage = "SELECT COUNT(*) FROM camps_events";
$result = mysql_query($query_perpage, $db) or die(mysql_error());
$r = mysql_fetch_row($result);
$numrows = $r[0];
$pages = new Paginator($query);
$pages->items_total = $numrows;
$pages->paginate();
$pages->mid_range = 7;
$query = mysql_query("SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC $pages->limit ") or die(mysql_error());
I've been trying to figure out how to paginate it by Program, no matter how many subrows.
I have a pagination class in place on another page, but that only pulls from one table.
I've been trying to implement the same pagination, but I can only get it to pull the first program, and then it limits the page based on the sub rows, not the main program row. And in the state I've posted it here, each following page displays only the first programs. The sub rows that come up are different on each page, but I can't tell if they are all in the first program.
The query works fine for pulling all results properly, but if it's a huge list, it's extremely inefficient, and can even timeout the browser.
Any help would be much appreciated, please let me know if I can include anything else.
I'm not too concerned with using the same pagination class, so I'm completely open to different approaches.
Thanks in advance
Try using a subselect:
SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
AND ce.id in (select id from camps_events pgce order by ce.eventdesc, ce.eventcode $pages->limit)
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC ")
or die(mysql_error());
Edit: unfortunately MySQL can not yet limit subqueries. :-(
So it has to be a temp-table:
mysql_query("drop temporary table if exists tmp_events", $db);
mysql_query("create temporary table tmp_events select id from camps_events order by eventdesc, eventcode " . $pages->limit, $db);
mysql_query("SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
inner join tmp_events pgce on pgce.id = ce.id
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC ")
or die(mysql_error());
There can be of course pages with less than paged items, because events without registrations will not show.

PHP comment system - echo matching foreign key and id

I'm creating a image gallery where people can add comments to each uploaded image.
I've made a db tabel for all comments including a foreign key to match the image table.
My SQL variable looks like this and seems to work fine:
$all_comments_one_image_sql="
SELECT userimage.id, image_id, comment, id, comment_date
FROM userimage, image_comment
WHERE image_comment.image_id=userimage.id
ORDER BY comment_id DESC
";
But when I'm doing my while function for all my gallery images, where and how would I echo the right comments to each image?
You should be doing a left join like this:
select userimage.id,
com.image_id,
com.comment,
com.id,
com.comment_date
FROM userimage
LEFT JOIN image_comment as com ON com.image_id=userimage.id
WHERE userimage.id = ?
ORDER BY com.id DESC
First of all create a function for getting image comments:
function getImageComments($imageId){
$query = "SELECT userimage.id, image_id, comment, id, comment_date
FROM userimage
LEFT JOIN image_comment
ON image_comment.image_id=userimage.id
WHERE image_id = $imageId
ORDER BY comment_id DESC
";
mysql_query($query);
return mysql_fetch....
}
I also redo your query for better performance.
So whnever you are loading an image, call the function with the proper image id and get its comments.
You have to check for the right image_id
$all_comments_one_image_sql = "
SELECT userimage.id, image_id, comment, id, comment_date
FROM userimage, image_comment
WHERE image_comment.image_id=userimage.id AND image_id = ?
ORDER BY comment_id DESC
";
where ? is the id of the image you want to Show comments - if you use pdo, you can just bind the image id and don't have to care about escaping.
If you have a summary page for all images, you can add the results in an assoc array, where the key is your image id
$comments[] = array();
while ($row = $res->fetch()) {
if (empty($comments[$row->image_id])) {
$comments[$row->image_id] = array();
}
$comments[$row->image_id][] = $row;
}
To show the comments, you can just look, if $comments[$image_id] is an array and show the conent

mysql: group results, limit them and join to other tables in one query

i have a online application for wich i require a sort of dashboard (to use the white-space).
There are three tables used for the operation:
1.) categories: id, name
2.) entries: id, name, description, category_id, created, modified
3.) entryimages: id, filename, description, entry_id
on the dashboard i want to show 4-5 entries (with thumbnail images, so i require joins to the entryimages table and the categories table) for each category.
I read through some articles (and threads on s.o.) like this one:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
But am still not getting it right, i've tried to first extract all categories and for each and every category build a query and with "all union" attach them to one, but that is not working.
The last version of code i used:
foreach($categories as $id => $name)
{
$query .= "SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry` LEFT JOIN `entryimages` ON `entryimages`.`entry_id` = `entry`.`id`
WHERE `entry`.`category_id` = $id ";
if($i < count($groups))
{
$query .= 'UNION ALL ';
}
$i++;
}
$result = mysql_query($query);
Does anybody know what is the best right to accomplish this operation?
Thanks 1000
On the dashboard if you want to show three entries, the way you are doing is wrong. If my understanding is right, the entire query will be something like
"SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry`
INNER JOIN categories
ON (entry.category_id = categories.id)
LEFT JOIN (SELECT * FROM `entryimages` WHERE `entry_id` = `entry`.`id` LIMIT 1) AS `entryimages`
ON `entryimages`.`entry_id` =`entry`.`id`
ORDER BY `entry`.`created` DESC LIMIT 5";
Your code looks ok to me you should just add a LIMIT clause so that you get just five of them and an ORDER BY clause to get the latest
$query .= "SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry` LEFT JOIN `entryimages` ON `entryimages`.`entry_id` = `entry`.`id`
WHERE `entry`.`category_id` = $id ORDER BY `entry`.`created` DESC LIMIT 5";

Trick Question; Showing 'nr of results' of MySql search

I have a classifieds website, and users can search ads.
The results are displayed in three tabs on top of the page. These three are "All", "Private", and "Company".
Each tab has a nr attached to it, which represents the nr of ads found in that tab.
So for example:
All Private Company
5 3 2
All is just a total of private+company!
I am using MySql as a database.
I am trying to figure out a way to find out these "numbers of ads found" for each tab.
I have one way of doing this, which is like this, but gives me a headache because it is so messy:
$query = "SELECT SQL_CACHE * FROM classified WHERE classified.classified_id=$id";
if ($adtypes=="Private"){
$query_priv_comp = "SELECT SQL_CACHE * FROM classified WHERE priv_comp='Company'";
}
else {
$query_priv_comp = "SELECT SQL_CACHE * FROM classified WHERE priv_comp='Private'";
}
switch ($adtypes){
case "Private":
$query.= " AND classified.priv_comp='Private'";
break;
case "Company":
$query.= " AND classified.priv_comp='Company'";
break;
}
$qry_result = mysql_query($query); // main query
$result_priv_comp = mysql_query($query_priv_comp); // second query
$num_priv_comp = mysql_num_rows($result_priv_comp);
if ($adtypes=="All"){
$num_total = mysql_num_rows($qry_result);
}
else if ($adtypes!="All"){
$num_total=mysql_num_rows($qry_result) + mysql_num_rows($result_priv_comp);
}
if ($adtypes=="Private"){
$num_private = $num_total - $num_priv_comp;
$num_company = $num_priv_comp;
}
else {
$num_company = $num_total - $num_priv_comp;
$num_private = $num_priv_comp;
}
Do you know of any other way which this can be done?
Thanks
BTW: I need the rows too, in order to display information to the user of the ads found!
It depends on what you need exactly. If you just need the counts it's relatively easy:
SELECT count(*) count_all
, sum(if(priv_com = 'Private', 1, 0)) count_private
, sum(if(priv_com = 'Company', 1, 0)) count_company
FROM classified
WHERE classified.classified_id=$id
If on the other hand, you need both counts as well as row data, you should either do separate queries for the data and the counts, or use a trick. Let's say your table has an id column wich is primary key, you could do:
SELECT count(*) count_all
, sum(if(priv_com = 'Private', 1, 0)) count_private
, sum(if(priv_com = 'Company', 1, 0)) count_company
, classified.*
FROM classified
WHERE classified.classified_id=$id
GROUP BY id -- group by on primary key
WITH ROLLUP
The WITH ROLLUP magic will give you an extra row with the counts for the entire query. The only snag is that you will receive this row as last row of the entire result, so if you want to report the counts before the data, you're going to have to cache the row data in an php array or so and process that later to build up the page.
After your switch variable
$query_priv_comp would be equal to:
SELECT SQL_CACHE * FROM classified WHERE priv_comp='Company'
AND classified.priv_comp='Private'
or
SELECT SQL_CACHE * FROM classified WHERE priv_comp='Private'
AND classified.priv_comp='Company'
Question: What the difference???
You can select all counts with one query:
SELECT priv_comp, COUNT(*) AS record_count FROM classified GROUP BY priv_comp
Then you can query all the records needed for the current tab.
These 2 should be separated clearly.

Categories