I'm trying to determine whether a combination of topics related to a category is unique. This is done while adding topics to a category. The uniqueness is checked with this query:
$sql_unique = "SELECT Categories_CategoryID, list
FROM (
SELECT Categories_CategoryID, GROUP_CONCAT( Topics_TopicID ) AS list
FROM (
SELECT *
FROM Topics_crosstable
ORDER BY Topics_TopicID
)H
GROUP BY Categories_CategoryID
)A
WHERE list = (
SELECT GROUP_concat( TopicID )
FROM Topics
WHERE Name = 'nr1'
OR Name = 'nr2'
ORDER BY Categories_CategoryID ASC )";
$result = mysql_query($sql_unique);
echo mysql_num_rows($result);
if($result > 1)
{
echo' HELP! It is not unique';
}
else
{
echo ' getshere';
}
This works fine. The problem is however, the number of topics that are added is variant. So is there some way to include a for loop in the where section of the query?
Something like for(number of topics added; nr++) {OR Name =', $inserted_topicName '}
Make use of 'WHERE ... IN':
WHERE Name IN ('nr1','nr2',...)
And
string implode ( string $glue , array $pieces );
Use as follows:
$options = array(); //here's your choices
$sql_unique = "SELECT Categories_CategoryID, list
FROM (
SELECT Categories_CategoryID, GROUP_CONCAT( Topics_TopicID ) AS list
FROM (
SELECT *
FROM Topics_crosstable
ORDER BY Topics_TopicID
)H
GROUP BY Categories_CategoryID
)A
WHERE list = (
SELECT GROUP_concat( TopicID )
FROM Topics
WHERE Name IN (";
$sql_unique .= implode(",",$options);
$sql_unique .= ") ORDER BY Categories_CategoryID ASC )";
table Categories
catID
table Topics
topID
category
Categories : Topics ( 1 : n )
Question: does category $x have unique set of topics?
first get sum of all topics of category $x
SELECT GROUP_CONCAT(topID ORDER BY topID) topiclist
FROM Topics
WHERE category='$x'
you may need to explode the topiclist and add some new values to that array, I am assuming that the result of the above query was fetched into an associative array $r
$list=explode(',',$r['topiclist']);
$list[]=$newtopicID1;
$list[]=$newtopicID2;
// etc ... or use $list += $newTopicsArray; which will ADD those two arrays
sort($list); //make it sorted again
$list=implode(',',$list);
and then query the database again, trying to find such a combination excluding the category i am querying:
SELECT GROUP_CONCAT(topID ORDER BY topID) topiclist
FROM Topics
WHERE category!='$x'
GROUP BY category
HAVING topiclist='$list'
then check whether there is some record returned. If so, then you found another category with the same topics, if not, then the combination of topics is unique
Related
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;
}
}
I'm having problem to sort table values by different categories of books and I'm having 10 categories of books.
Categories are mentioned in a table entitled "categories" as (1, 2, 3,...10) and each category contains more than 100 books.
I just want to sort books only by one category such as 1 from my database and ignore all the other categories.
I used following php codes but it sorted the results as whole of column "categories" that means all the categories are sorted one by one but
I just want to sort data by single category.
$orderby = "ORDER BY books.category DESC";
$addparam = "";
if ($_GET["incldead"] == 2)
$wherea[] = "visible = 'yes'";
$res = mysql_query("SELECT COUNT(*) FROM books $where") or die(mysql_error());
$row = mysql_fetch_array($res,MYSQL_NUM);
$count = $row[0];
if ($count)
{
$pager = pager($booksperpage, $count, "browse.php?" . $addparam);
$query = "SELECT books.id, books.category, books.name, books.times_completed, books.size, books.added, books.type, books.comments,books.numfiles,books.filename,books.owner,IF(books.nfo <> '', 1, 0) as nfoav," .
"categories.name AS cat_name, categories.image AS cat_pic, users.username FROM books LEFT JOIN categories ON category = categories.id LEFT JOIN users ON books.owner = users.id $where $orderby {$pager['limit']}";
$res = mysql_query($query) or die(mysql_error());
Output of above code similar to below:
My desired output:
Please guide me how it'll be possible by amending in above php codes...
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";
I have this query:
$result = mysql_query("SELECT id,pic0,bio,url FROM ".$table." WHERE id LIKE '%custom%' || ( category IN ('cat1') AND model = 'bmw'");`
And I am displaying them in a loop like:
while ($slice = mysql_fetch_assoc($result)){ }
Is there a way to firstly display the records from: WHERE id LIKE '%custom%'
And after display the records from: || ( category IN ('cat1') AND model = 'bmw'");
Ty for your answer.
Here is an updated sql code which I did to be sure the duplicates are removed automaticly:
(
SELECT 1 AS sort_col, performerid, pic0
FROM `cronjob_reloaded`
WHERE performerid IS NOT NULL
)
UNION (
SELECT 2 AS sort_col, performerid, pic0
FROM `cronjob_reloaded`
WHERE performerid IS NOT NULL
AND category
IN (
'Girl'
)
)
ORDER BY sort_col
And they are not. The first select gets the same result as the select nr two, but mysql shows me all the rows combined.
you could use a union
$result = mysql_query("(SELECT 1 as sort_col,id,pic0,bio,url FROM ".$table." WHERE id LIKE '%custom%') UNION (SELECT 2 as sort_col,id,pic0,bio,url FROM ".$table." WHERE category IN ('cat1') AND model = 'bmw') order by sort_col";
edit: removed the warning about duplicates (according to mysql union docs, dupes are removed automatically), added sort_col to make sure the order is kept.
what about this?
SELECT id,pic0,bio,url
FROM ".$table."
WHERE id LIKE '%custom%' || ( category IN ('cat1') AND model = 'bmw'")
ORDER BY (id LIKE '%custom%') DESC;
I would put the results into two different variables based on a conditional, then output the variables in whatever order you like outside the loop. Because there may be things that might satisfy both parts of the query, the conditional would be what you think is really important to separate. So if it's crucial that the bmw results go last you could do something like:
//In Loop
$model = $slice['model'];
if($model != bmw){
$displayFirst.= $RecordsToDisplay;
}
else{
$displaySecond.= $RecordsToDisplay;
}
//End Loop
echo $displayFirst;
echo $displaySecond;
**categories** mysql table
id|category_name
**listings** mysql table
id|listing_title|category_id
I want to list all categories on 1 single/same PHP page, with all the listings shown below each category. How can I do this by querying the listings table ONCE. I can do it by making a separate query from within the categories loop, but that would be more than necessary I'm guessing.
//query listings table once
$sql = mysql_query("SELECT * FROM listings", $conn);
//loop through all categories
$sql = mysql_query("SELECT * FROM categories ORDER BY catname", $conn);
while($row= mysql_fetch_array( $sql, MYSQL_ASSOC )){
//print category name
print"$row[catname]";
//print listings of category
}
Here is simple one (Category Name,Listings)
$sql_code = "SELECT C.category_name cat_name,L.listing_title listings FROM categories C,listings L WHERE C.id = L.category_id ORDER BY C.category_name";
$next_catname="";
while($row= mysql_fetch_array( $sql, MYSQL_ASSOC )){
if ( strcmp($next_catname,$row[catname]) < 0 )
{
if ( strlen($next_catname) > 0 ){ print "<\BR>": }
print "Category : " . $row[catname] . "<\BR>";
}
print"$row[catname] : $row[listings]<\BR>";
}
Here is a freaky one (Category Name Along with Comma-Separated List of Listings)
$sql_code = "SELECT C.category_name cat_name,GROUP_CONCAT(L.listing_title) listings FROM categories C,listings L WHERE C.id = L.category_id GROUP BY C.category_name";
$sql = mysql_query($sql_code, $conn);
while($row= mysql_fetch_array( $sql, MYSQL_ASSOC )){
print"Category: $row[catname]<\BR>Listings: $row[listings]<\BR><\BR>";
}
or you could explode $row[listing] by ',' and print them one by one
Have fun with this one !!!
have you thought about
select * from categories, listings
where categories.id = listings.category_id
order by categories.name, categories.id, listings.listing_title, listings.id
then having the PHP code loop through the list keeping track of whether the current category matches the previous category?