mysql group by php concat - mysql

I have a table of fixtures in my DB: hometeam, awayteam, date, time
I am currently using mysql_fetch_array and getting the following:
hometeam awayteam date time
--------------------------------------------
Blackburn Wolves 13/08/2011 3:00pm
Arsenal Liverpool 13/08/2011 3:00pm
etc
I want to return:
13/08/2011
---------------------------
Blackburn, Wolves, 3:00pm
Arsenal, Liverpool, 3:00pm
etc
I have tried group by date, but this just returns 1 fixture for that date which is rubbish.
I have also tried group_concat, but the problem with this is I need to modify the items in this group, such as changing the time format from server time to a readable time like above.

you can sort by date and then check in php when the date changes between two rows. something like this:
function h($s) { return htmlspecialchars($s); }
$conn = mysqli_connect(…);
$result = mysqli_query($conn, 'select * from fixtures order by date');
$lastdate = NULL;
while(($row = mysqli_fetch_assoc($result)) !== FALSE) {
if($lastdate != $row['date']) {
// output date divider/header
echo '<h1>',h($row['date']),'</h1>';
$lastdate = $row['date'];
}
echo h($row['hometeam']), ', ', h($row['awayteam']), ', ', h($row['time']);
}

Related

database query to get lowest price based on last crawel date

I would like to get lowest price of product based on last crawled dates by various resellers. My current function is very basic, it gets me lowest price from table without considering reseller ids and crawled timestamps.
I've rough idea that we can SELECT * FROM "custom_data_table" and process the data using php. Please have a look at attachment for further clarification.
function get_lowest_price($table_id) {
global $wpdb;
$table_prices = $wpdb->get_results(
$wpdb->prepare(
"SELECT price FROM `custom_data_table` WHERE tableid= %d"
,$table_id)
);
if (!empty($table_prices) && $table_prices !== NULL)
return rtrim(min($table_prices)->price, '00');
}
The right query here is:
SELECT price
FROM custom_data_name cdn, (
SELECT MAX(crawled) AS maxCrawled, resellerid
FROM custom_data_name
GROUP BY resellerid
) cdnFiltered
WHERE cdn.crawled = cdnFiltered.maxCrawled AND
cdn.resellerid = cdnFiltered.resellerid AND
tableid = %d;
Try this:
SELECT B.price
FROM (SELECT resellerid, MAX(crawled) max_crawled
FROM custom_data_table
GROUP BY resellerid) A
JOIN custom_data_table B
ON A.resellerid=B.resellerid AND A.max_crawled=B.crawled;
Maybe use ORDER BY crawled and LIMIT 1

sql get booking clashes between two times

I have a sql booking question. The table has idstylist, bdate, stime and etime.
Basically the stylist can only do one job at a time. So when placing a booking I need to check that that stylist is not already busy on another booking. Here is my clash method;
public function checkClash($bdate, $stime,$stylist){
$query = sprintf("SELECT id FROM table WHERE (date=%s AND idstylist=%s) AND (%s BETWEEN stime AND etime)",
$this->db->GetSQLValueString($bdate, "date"),
$this->db->GetSQLValueString($stylist, "int"),
$this->db->GetSQLValueString($stime, "text"));
$result = $this->db->query($query);
if($result && $this->db->num_rows($result) > 0){
return true;
}
return false;
}
As far as I understand my query is selecting all bookings from (date) where idstylist is this and the start time is >= $stime but <=$stime.
So for example I have a row in the database that looks like this;
id | date | idstylist | stime | etime
1 | 2014-12-05 | 68 | 07:00:00 | 07:30:00
Now Im trying to place a booking for the same stylist at 07:10:00 on the same date which should fail but the system is allowing me to make this booking. I cant see whats wrong with my query.
//next check for clashes in the booking table
$clash = $bookings->checkClash($_POST['bdate'],$_POST['stime'], $_POST['stylist']);
if($clash==true){
$errors[] = "Booking clashes. Please try again";
}
This is turning into a debugging session.
From your SQL: (stime>=%s AND etime<=%s)
Replace with values: ('7:00' >= '7:10' AND '7:30' <= '7:10')
I gues you want: (%s BETWEEN stime and etime)

mysql select count(column) where sum(column) > value

I'm trying to query $wpdb to get back an int value of the number of users in a custom table who have recorded a number of hours volunteer work above a set target - these hours need to have been moderated ( value set to = 1 ) - I have this so far:
EDIT - updated to use consistent {} around php variables in query --
$target = get_post_meta($post->ID, 'target', true) ? (int)get_post_meta($post->ID, 'target', true) : 100;
$awards = $wpdb->get_var("
SELECT user_id
FROM {$this->options['rewards_logging']}
WHERE moderated = 1 AND reward_id = {$post->ID}
GROUP BY user_id
HAVING sum(hours) > {$target}
");
Which returns the correct value of '0' if none of the hours are approved ( moderated = 0 ), however as soon as one of those users hours are approved, this query returns the count of all the users who have logged more than the target hours ( whether they have been approved or not ).
Any pointers!
Cheers
Ray
Seems I was trying to get back a single variable using $wpdb->get_var, when I really needed the whole result set:
$awards = $wpdb->get_results("
SELECT user_id
FROM {$this->options['rewards_logging']}
WHERE moderated = 1 AND reward_id = {$post->ID}
GROUP BY user_id
HAVING sum(hours) > {$target}
");
Then I can check over the data and display a result - etc...:
if ( count($awards) > 0 ) {
#var_dump($awards);
echo '<span class="awards-notice">'.count($awards).'</span>';
} else {
echo '-';
}

php mysql group by date with yyyy-mm-dd format

I had a mysql table called events with the fields: id, date, and name.
The date field has the format yyyy-mm-dd hh::mm:ss edit: meaning it is in datetime format
I want to group the events by day, and I wasn't sure how to approach this- is there a way to select only the month and day from the field? or should i use PHP after I select all the "events"
my end goal is to have something like this:
March 10th:
event1,
event2
March 11th:
event4,
event5
I found MySQL select using datetime, group by date only but I'm not sure how to implement it:
SELECT DATE_FORMAT(date, '%H%i'), DATE_FORMAT(date, '%M %D'), name FROM events ORDER BY date
Thanks!
EDIT:
ended up using this:
$sql = "select team1, team2, DATE_FORMAT(date,'%Y-%m-%d') as created_day FROM games WHERE attack = '1' GROUP BY created_day";
$result = mysql_query($sql);
$curDate = "";
while (list($team1, $team2, $date) = mysql_fetch_row($result))
{
if ($date != $curDate)
{
echo "$date --------\n";
$curDate = $date;
}
echo "game data: $team1 $team2";
}
If you use group by you will not get one row out of it. So the way you want is not possible through Group By AFAIK.
$query = "SELECT distinct(DATE_FORMAT(date, '%M %D')) as d FROM yourtable";
$result = mysql_query($query);
while($row = mysql_fetch_assoc($result)) {
echo $row['d']
$sql = "SELECT * FROM yourtable WHERE DATE_FORMAT(date, '%M %D')='$row[d]'";
$rs = mysql_query($query);
while($r = mysql_fetch_assoc($rs)) {
echo "event";
}
}
You should indeed use php to get this done. But since most of current system sepate logic from display, I'd use only one pass and not (NUMBER OF DAYS + 1) SELECTs, and prepare an array that I can reuse later for my display.
$query = "SELECT DATE_FORMAT(date, '%M %D') as d, name FROM yourtable ORDER BY date";
$foo=array();
$result = mysql_query($query);
while($row = mysql_fetch_assoc($result)) {
//some logic to test if it's safe to add the name
$foo[$row['d']][]=$row['name'];
}
And then when i'd need it (through a template or your "view")
foreach($foo as $date => $events) {
echo $date . ":\n\t";
echo implode(",\n\t", $events);
echo "\n";
}
so it fits the format you set to yourself.
Hope that helped
I think from that question/answer, you can get something like this instead
March 10th, event1
March 10th, event2
March 11th, event4
March 11th, event5
It does not really 'group' dates as your wish but I think you can use php to continue from this result.
I agree with Kharaone, separate logic from display. That being said, I think that something similar to this query might be what you are looking for:
SELECT A FROM
(
SELECT DATE_FORMAT(date,'%M %D:') AS A, DATE(date) AS B, 1 AS C FROM games GROUP BY DATE(date)
UNION ALL
SELECT name AS A, DATE(date) AS B, 2 AS C FROM games
) X
ORDER BY B, C ASC;

Why doesn't this SELECT query return the results I expect?

I need help with a select query, but before asking the question, I will give a short description of how my system works:
My database has a many-to-many relationship:
table product:
prd_cod(pk) //stores the product code ex: 0,1,2
cat_cod(fk)
prd_name //stores the product name, ex: tv, gps, notebook
table description_characteristc:
prd_cod(fk)
id_characteristic(fk)
description //stores the description of the characteristic, ex: sony, 1kg, hj10
table characteristic:
id_characteristic (pk)
name_characteristic //store the name of characteristic, ex: brand, weight, model
I have already made a suggest jQuery (in the index.php), where every word I type calls suggest.php, which makes a select and returns the result into the suggestion box in the index:
<?php
header('Content-type: text/html; charset=UTF-8');
$hostname = 'localhost';
$username = 'root';
$password = '';
$dbname = 'cpd';
mysql_connect($hostname, $username, $password)or die('Erro ao tentar conecta o banco
de dados.');
mysql_select_db( $dbname );
if( isset( $_REQUEST['query'] ) && $_REQUEST['query'] != "" )
{
$q = mysql_real_escape_string( $_REQUEST['query'] );
if( isset( $_REQUEST['identifier'] ) && $_REQUEST['identifier'] == "sugestao")
{
$sql = "SELECT p.prd_name, d.description
FROM product p
INNER JOIN description_characteristc d using (prd_cod)
WHERE '".$q."' like concat(p.prd_name, '%') AND
concat(p.prd_name, ' ', d.description) like concat('".$q."', '%')LIMIT 10";
$r = mysql_query( $sql );
if ( $r )
{
echo '<ul>'."\n";
$cont = 0;
while( $l = mysql_fetch_array( $r ) ){
$p = $l['nome'];
$p = preg_replace('/(' . $q . ')/i', '<span style="font-
weight:bold;">$1</span>',
$l['prd_nome'].' '.$l['descricao'].' '.$l['descricao']);
echo "\t".'<li id="autocomplete_'.$cont.'"
rel="'.$l['prd_nome'].'.'.$l['descricao'].'">'. utf8_encode( $p ) .'</li>'."\n";
$cont++;
}
echo '</ul>';
}
}
}
?>
Here are my questions:
Currently when the user types 't', the select brings nothing, only when the user type 'tv' is bringing the result:
tv led
tv plasm
tv samsumg
I would like that when the user type 't' the select bring me 'tv'.
When you type 'tv plasm' it's bringing the same name_characteristic twice:
ex: tv plasm plasm
Currently my select selects the prd_name and the descriptions of table description_characteristc:
tv led
I would like my select could make a inverse select too, ex: led tv.
I would like that when the results of the select were shown, there could be a cache feature that shows the order of the most sought for the less sought; remembering that prd_name stores only 'tv'.
The help I'm looking for can be in the form of select, as in the form of procedure. Also, I can edit the php file.
You should split and join your search query on PHP side like this:
<?php
$words = preg_split("/[^\\w]+/", $q);
$first = $words[0] + "%";
$all = implode(" ", $words) + "%";
?>
then use the variables $first and $all in this query:
SELECT p.prd_name, d.description
FROM product p
JOIN description d
ON d.prd_cod = p.prd_cod
WHERE p.prd_name LIKE '$first'
AND CONCAT(p.prd_name, ' ', d.description) LIKE '$all'
Create an index on product (prd_name) for this to work fast.
If you want the words matched in any order, you will have to create a FULLTEXT index on your tables (this is only possible in MyISAM):
CREATE FULLTEXT INDEX fx_product_name ON product (prd_name)
CREATE FULLTEXT INDEX fx_description_name ON description (description)
and write a query like this:
SELECT p.prd_name, d.description
FROM (
SELECT prd_cod
FROM product pi
WHERE MATCH(prd_name) AGAINST ('lcd tv' IN BOOLEAN MODE)
UNION
SELECT prd_cod
FROM description di
WHERE MATCH(description) AGAINST ('lcd tv' IN BOOLEAN MODE)
) q
JOIN product p
ON p.prd_cod = q.prd_cod
JOIN description d
ON d.prd_cod= p.prd_cod
WHERE MATCH(p.prd_name, d.description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
Note the search term syntax change: 'lcd tv' in the inner query and '+lcd +tv' in the outer one.
You may also want to set ##ft_min_word_len to 1 for the shorter words like tv or gps to match.
Since MySQL cannot build a fulltext index from two or more tables at once, it would be more simple if you denormalized you tables and put the prd_name into the description table. This way, you could get rid of the joins and just write:
SELECT prd_name, description
FROM description d
WHERE MATCH(prd_name, description) AGAINST ('+lcd +tv' IN BOOLEAN MODE)
You're using the LIKE clause badly and you don't seem to know what "AND" means. It's important to separate "and" as used in casual speech from "AND" as used in programming. AND in programming means "BOTH MUST BE TRUE". "and" in casual speech can mean "one of these conditions, you know what I mean?"
Also, you shouldn't be building SQL like this, it's an accident waiting to happen. You really should find a way to bind variables into SQL statements. I don't know PHP, so I can't help with that.
First, you should be using this in your WHERE clause p.prd_name LIKE '$q%'. Try this outside PHP -- outside the web -- just as a simple SQL query: SELECT * FROM PRODUCT P WHERE P.PRD_NAME LIKE 'T%'.
Second, you should fix "AND" to be "OR", since you want one condition OR the other condition to be true. If you want for BOTH conditions to be true, hardly anything will match.