First time using CASE in PDO (mySQL database)
I'm trying to ORDER BY a date, but only if the date is not 0000-00-00 (it can be)
But it seems to ignore the case all together.. What am I doing wrong?
$sql = 'SELECT * FROM mytable WHERE groupid = '.$groupid.' ORDER BY CASE WHEN groupdate != "0000-00-00" THEN groupdate END ASC';
$STH = $conn->query($sql);
if ($STH->rowCount() > 0) {
while ($row = $STH->fetch()) {
// output the rows
}
} else {
echo '<p>No dates found!</p>';
}
What do you want to do with zero-date rows?
Return them after other rows?
Then use this query
SELECT *
FROM mytable
WHERE groupid = $groupid
ORDER BY groupdate = '0000-00-00', groupdate
groupdate = '0000-00-00' is a boolean expresion and returns 1 for matching rows, 0 for non-matching rows. 0 comes before 1 in ascending order.
Non-zero rows are sorted by groupdate.
As you can read in the CASE documentation you should have an ELSE statement in the end. Try something like:
$sql = 'SELECT * FROM mytable WHERE groupid = '.$groupid.' ORDER BY (CASE WHEN groupdate != "0000-00-00" THEN groupdate ELSE groupid END)';
Related
I have this code
$db = \Config\Database::connect();
$query = $db->query("select * from g WHERE g_status = '0' ORDER BY g_date ASC Limit 10;");
foreach ($query->getResult() as $g) {
$g_amount = $g->g_amount;
}
$query2 = $db->query("select * from g WHERE p_status = '0' ORDER BY p_date ASC Limit 10;");
foreach ($query2->getResult() as $p) {
$p_amount = $p->p_amount;
}
if($p_amount == $g_amount){
echo "do something";
}else{
echo "No match";
}
Here I am trying to match between table g and table p.... if any column in table g is == any column in table p regardless of the number of column, do something but it always echo "NO match"
I put "Limit 10" in case there is much number of rows in the table, it will only match the first 10th row with the "ordering" command.
Please I need some help.
First, get data as an array
$db = \Config\Database::connect();
$query = $db->query("select * from g WHERE g_status = '0' ORDER BY g_date ASC Limit 10;");
$g_results = $query->getResult('array');
$g_amounts = array_column($g_results,'g_amount');
$query2 = $db->query("select * from g WHERE p_status = '0' ORDER BY p_date ASC Limit 10;");
$p_results = $query2->getResult('array');
$p_amounts = array_column($p_results,'p_amount');
foreach(array_intersect($g_amounts,$p_amounts) as $amount){
echo "do something";
}
Why not use a JOIN and see if it returns something? Not sure if my syntax is correct, I don't do JOINs very often:
SELECT * FROM g g_table JOIN p p_table ON g_table.g_amount = p_table.p_amount WHERE g_table.status = '0' AND p_table.status = '0'
I have two tables in a database, one of them is a list of 'buildings' you could create. The other is a list of buildings that have been built by users.
On one page, (cityproduction.php), it displays a list of 'buildings' you can build.
I want it to display the buildings that you can build, that you haven't already built.
Here is my code:
$sql = "SELECT * FROM [The list of built buildings] WHERE building_owner = '$user'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$variable = $row["building_name"];
}
(...)
$sql = "SELECT * FROM [The list of ALL buildings] WHERE name != '$variable' ORDER BY id asc";
$result = mysqli_query($database,$sql) or die(mysqli_error($database));
while($rws = mysqli_fetch_array($result)){
echo $rws["name"]; (etc.)
What this is doing is only not-showing one of the buildings that the user has built, not all of them.
Without seeing the real table names or the schema it is tricky to answer accurately but you could try something along these lines:
SELECT * FROM `all_buildings`
WHERE `id` not in (
select `building_id` from `built_buildings` where `building_owner` = '$user'
)
ORDER BY `id` asc;
Another translation of your question into SQL (besides NOT IN) results in a Correlated Subquery:
SELECT * FROM `all_buildings` AS a
WHERE NOT EXISTS
(
select * from `built_buildings` AS b
where a.`id` = b.`building_id` -- Outer Select correlated to Inner
and b.`building_owner` = '$user'
)
ORDER BY `id` asc;
The main advantage over NOT IN: it's using only two-valued-logic (NULL is ignored = false) while NOT IN uses three-valued-logic (comparison to NULL returns unknown which might no return what you expect)
Why are you using while after the first query, it suppose to be a list or just a single value? because if you use $variable in your second query it will only have the value of the last value of the list you are getting
if ($result->num_rows > 0) {
$variable = array();
while($row = $result->fetch_assoc()) {
$variable[] = $row["building_name"];
}
Second query example:
foreach($variable as $building) {
$sql = "SELECT * FROM [The list of ALL buildings] WHERE name != '$building' ORDER BY id asc";
$result = mysqli_query($database,$sql) or die(mysqli_error($database));
$result = mysqli_fetch_assoc($result);
echo $result["name"];
}
Assuming both of your tables have some sort of id column to relate them, with this query:
SELECT building_name, building_owner FROM
test.all_buildings a
LEFT JOIN test.built_buildings b ON a.id = b.building_id AND b.building_owner = ?
ORDER BY building_owner DESC, building_name;
(where ? is the user), you can select all the buildings, first the ones that have been built, followed by the ones that haven't, in one query. If your tables don't have id's like that, you can join them on name instead; it should work as long as the names are distinct.
Then as you fetch the rows, you can sort them into "built" or "not built" by checking if the row has a building_owner.
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
if ($row['building_owner']) {
$built[] = $row['building_name'];
} else {
$not_built = $row['building_name'];
}
}
}
The code I have below joins 5 tables and then is suppose to sort by date_timed_added. The query worked perfectly if i only join 4 tables. For some reason after the 4th table, its giving me issues. The issue is that it sorts and displays the 5th table first and then the rest follow. How can i fix it so that it sorts date_time_added properly by querying all the other tables?
//$sid is a variable that is drawn from DB
$sql = "select `client_visit`.`visit_id`, `client_visit`.
`why_visit`, `client_visit`.`date_time_added`, `client_visit`.
`just_date`, `client_visit`.`type` from `client_visit` where
`client_visit`.`system_id` = '$sid' and `client_visit`.
`added_by` = '$sid'
UNION
select `client_notes`.`note_id`, `client_notes`.`note_name`,
`client_notes`.`date_time_added`, `client_notes`.`just_date`
, `client_notes`.`type` from `client_notes` where `client_notes`.
`added_by` = '$sid'
UNION
select `client_conditions`.`med_id`, `client_conditions`.`med_name`,
`client_conditions`.`date_time_added`, `client_conditions`.`just_date`,
`client_conditions`.`type` from `client_conditions` where
`client_conditions`.`system_id` = '$sid' and `client_conditions`.
`added_by` = '$sid'
UNION
select `client_stats`.`stat_test_id`, `client_stats`.`stat_why`,
`client_stats`.`date_time_added`, `client_stats`.`just_date`,
`client_stats`.`type`
from `client_stats` where `client_stats`.`system_id` = '$sid'
and `client_stats`.`added_by` = '$sid'
UNION
select `client_documents`.`doc_id`, `client_documents`.`doc_name`,
`client_documents`.`date_time_added`, `client_documents`.`just_date`,
`client_documents`.`type` from `client_documents` where `client_documents`.
`system_id` = '$sid' and `client_documents`.`added_by` = '$sid'
ORDER BY `date_time_added` DESC LIMIT $startrow, 20";
$query = mysql_query($sql) or die ("Error: ".mysql_error());
$result = mysql_query($sql);
if ($result == "")
{
echo "";
}
echo "";
$rows = mysql_num_rows($result);
if($rows == 0)
{
}
elseif($rows > 0)
{
while($row = mysql_fetch_array($query))
{
//Just using these two variables i can display the same row info
//for all the other tables
$stuffid = htmlspecialchars($row['visit_id']);
$title = htmlspecialchars($row['why_visit');
}
}
}
As per the MySQL docs: http://dev.mysql.com/doc/refman/5.0/en/union.html
If you want to order the ENTIRE result set, the ORDER BY clause must be placed on the LAST query in the UNION, with each query being bracketed.
(SELECT ...)
UNION
(SELECT ...)
ORDER BY ...
sth like this should do.
SELECT Tbl1.field1
FROM ( SELECT field1 FROM table1
UNION
SELECT field1 FROM table2
) Tbl1
ORDER BY Tbl1.field1
Pseudocode
$res = Query("SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15");
SortArray(&$res, 'date', 'asc');
If describe in words, then take the last part of the data is sorted in descending order from the database, but to give the data sorted in ascending order.
Try:
$res = Query("SELECT * FROM ( SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15) ORDER BY `date` ASC");
You can use a usort function to sort the array by specific key:
$res_array=array();
while($row=mysql_fetch_row($res))
$res_array[]=$row;
$new_arr = usort($res_array,"my_func");
function my_func($a, $b)
{
if ($a['date'] == $b['date']) {
return 0;
}
return ($a['date'] < $b['date']) ? -1 : 1;
}
*may need some debugging. take the idea.
Instead of making some magical SQL query, you should select 15 first rows in descending order. And then just read the results from the end.
$statement = $pdo->query('SELECT * FROM `table` ORDER BY `date` DESC LIMIT 15');
if ( ! $statement->execute())
{
throw new Exception('query failed !');
}
$data = $statement->fetchAll(PDO::FETCH_ASSOC);
while ( $row = array_pop($data))
{
var_dump( $row );
}
My page displays an image, and I want to display the previous and next image that is relevant to the current one. At the moment I run the same query 3x and modify the "where" statement with =, >, <.
It works but I feel there must be a better way to do this.
The image id's are not 1,2,3,4,5. and could be 1,2,10,20,21 etc. But if it is much more efficient I am willing to change this.
mysql_select_db("database", $conPro);
$currentid = mysql_real_escape_string($_GET['currentid']);
$query ="SELECT * FROM database WHERE id ='".$currentid."' LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$current_id = $row['id'];
$current_header = $row['title'];
$current_description =$row['desc'];
$current_image = "http://".$row['img'];
$current_url = "http://".$row['id']."/".$db_title."/";
$current_thumb = "http://".$row['cloud'];
}
mysql_select_db("database", $conPro);
$query ="SELECT * FROM database WHERE id <'".$currentid."' ORDER BY id DESC LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$previous_id = $row['id'];
$previous_header = $row['title'];
$previous_description =$row['desc'];
$previous_image = "http://".$row['img'];
$previous_url = "http://".$row['id']."/".$db_title."/";
$previous_thumb = "http://".$row['cloud'];
}else{
$previous_none = "true"; //no rows found
}
mysql_select_db("database", $conPro);
$query ="SELECT * FROM database WHERE id >'".$currentid."' ORDER BY id ASC LIMIT 1 ";
$result = mysql_query($query,$conPro) or die(mysql_error());
$affected_rows = mysql_num_rows($result);
if ($affected_rows==1)
{
$row = mysql_fetch_array($result)or die ('error:' . mysql_error());
$next_id = $row['id'];
$next_header = $row['title'];
$next_description =$row['desc'];
$next_image = "http://".$row['img'];
$next_url = "http://".$row['id']."/".$db_title."/";
$next_thumb = "http://".$row['cloud'];
}else{
$next_none = "true"; //no rows found
}
mysql_close($conPro);
Thank you for your time
You don't have to do select_db each time. Once you 'select' a db, it stays selected until you select something else.
You can't really get away from doing two separate queries to get the next/previous images, but you can fake it by using a union query:
(SELECT 'next' AS position, ...
FROM yourtable
WHERE (id > $currentid)
ORDER BY id ASC
LIMIT 1)
UNION
(SELECT 'prev' AS position, ...
FROM yourtable
WHERE (id < $currentid)
ORDER BY id DESC
LIMIT 1)
This would return two rows, containing a pseudofield named 'position' which will allow you to easily identify which row is the 'next' record, and which is the 'previous' one. Note that the brackets are required so that the 'order by' clauses apply to the individual queries. Without, mysql will take the order by clause from the last query in the union sequence and apply it to the full union results.
You can get the "previous" one first WHERE id <'".$currentid."' ORDER BY id DESC, and then query for two "above" it: SELECT * FROM database WHERE id >= '".$currentid."' ORDER BY id ASC then it takes only two queries instead of three.