SQL select with DATE in WHERE, what is faster? - php

I have a query from table of rows, where is datetime column with only year and month.
The day is always 01 and time is 00:00:00
When selecting data with php query, what is faster?
$date = "2020-04";
$query = "SELECT * FROM table WHERE datum LIKE ?",$date ;
or
$date = "2020-04";
$rok = substr($mesic,0,4);
$mesic = substr($mesic,5,2);
$query = "SELECT * FROM table WHERE YEAR(datum) = ? AND MONTH(datum) = ?",$rok,$mesic;
The table contains 100s thousands of rows

We always used to have the rule:
"Avoid functions in the WHERE Clause".
The background is that the database server has to make a table scan to calculate the function result for each row (even if it is only the key table).
So he cannot use the keys efficiently!
LIKE is faster!
If you use the beginning of the key (as you write), it can also use it efficiently.

I would recommend:
$date = "2020-04";
$sql = "SELECT * FROM table WHERE datum = concat(?, '-01')", $date;
The base idea is not not apply functions (either date functions or pattern matching) on the column being searched, as this prevents the database from taking full advantage of an index on that column (and it involves unnecessary additional computation for each and every row). Instead, you can easily generate the exact value to search for with by concatenating the variable in the query.
In the more typical case where datum had real day and time components, and you want to filter on a given month, you would do:
SELECT *
FROM table
WHERE datum >= concat(?, '-01') AND datum < concat(?, '-01') + interval 1 month
Note that this assumes that you are using MySQL, because the syntax suggests it. Other database have equivalent ways to build dates from strings.

Neither. In both cases you have a function call on the datum column. With YEAR() and MONTH() it is obvious. With LIKE you are converting to a string. Both impede the optimize and prevent the use of indexes.
The correct structure would be:
where datum >= ? and
datum < ? + interval 1 month -- syntax might vary depending on the database
where ? are parameter place-holders for the beginning of the month. I would suggest that you construct this in the application as a date constant or a string constant of the canonical form YYYY-MM-DD.

Related

show information from database based on dates mysql

I have a database table that contains information and has columns 'Date Start' and 'Date End'
I'm wondering if there is a way to show data from the database between those dates.
So for example let's say i schedule something on the 1st december and then it ends on the 3rd. This is my current query
<?
$query2 = mysql_query ( "SELECT * FROM `Announcements` " );
$announecment = mysql_fetch_object ( $query2 ) ;
<div class="page-bg" style="background-image: url('<?echo $announecment->backgroundim;?>');"></div>
<?}?>
Since you did not provide the names for the columns, I'm going to use date_start and date_end to represent them, but you need to use the actual column names.
The query you are looking for is something like this:
SELECT * FROM `Announcements` WHERE `date_start` < NOW() AND `date_end` > NOW();
This is under the assumption that those timestamps are set by the database. If they are set within the application logic and the timezones do not match, this may still give you issues. In that case, instead of using NOW(), you will want to use the php date function to generate a date, and pass that in in place of using the MySQL NOW() construct.
You also will want to use prepared statements, as mentioned in the comments on your original question to avoid SQL injection vulnerabilities.

Get all rows from a specific month and year

I have a PHP scirpt that is always querying all the data from a database table and it's getting pretty slow. I really just need the data of a specific month and year.
Is there a simple way to get only those entries? For example, everything from February 2013?
The column that stores the dates in my table is of type datetime, if that applies to the solution.
You can add that condition in the WHERE clause of your select statement. I would recommend using BETWEEN operand for two dates:
SELECT myColumns
FROM myTable
WHERE dateColumn BETWEEN '2013-02-01' AND '2013-02-28';
If you mean to say you want everything beginning with February 2013, you can do so using the greater than or equal to operator:
SELECT myColumns
FROM myTable
WHERE dateColumn >= '2013-02-01';
EDIT
While the above are my preferred methods, I would like to add for completeness that MySQL also offers functions for grabbing specific parts of a date. If you wanted to create a paramaterized query where you could pass in the month and year as integers (instead of a start and end date) you could adjust your query like this:
SELECT myColumns
FROM myTable
WHERE MONTH(dateColumn) = 2 AND YEAR(dateColumn) = 2013;
Here is a whole bunch of helpful date and time functions.
You should index the datetime field for added efficiency and then use Between syntax in your sql. This will allow the mysql engine to remove all records that you are not interested in from the returned data set.

More efficient way to perform multiple MySQL queries in PHP

I have an online store with thousands of orders and I'm writing some queries to figure out how much money each supplier (brand) has made on the site. I have the following queries, one for every month of the selected year:
$filterJan = "$filterYear-01";
$queryJan = "SELECT price, quantity FROM order_items WHERE productID='$productID' AND timestamp LIKE '%$filterJan%' LIMIT 10000";
$suppliersQueryFilter = mysql_query($queryJan, $connection) or die(mysql_error());
while($rowF = mysql_fetch_assoc($suppliersQueryFilter)) {
$price = $rowF["price"]*$rowF["quantity"];
$totalJan = $totalJan+$price;
}
** and so on for each month **
It takes ages to load (we're talking over 60 seconds at least) and I know it is not efficient in any shape or form. For each month these queries are searching through thousands of records. Is there a more efficient way or writing this to:
a) Reduce the amount of code to maybe 1 query
b) Make it more efficient to increase loading times
$filterYear contains a year, like 2009.
So what this query does is it selects how much money has been made for each month for a selected year (which is assigned to $filterYear). So the result it generates is a table with Jan, Feb, March... with how much money has been made each month, so £2345, £2101, etc...
You should be storing your timestamp as an actual mysql datetime value, which would make things like
GROUP BY YEAR(timestamp), MONTH(timestamp)
WHERE timestamp BETWEEN $initialtime AND $finaltime
trivially possible. That'd reduce your multiple essentially identical repeated queries to just one single query.
You can use derived values for this, but it'll be less efficient than using a native datetime field:
GROUP BY SUBSTR(timestamp, 0, 4), SUBSTR(timestamp, 6,2)
For best performance, you'd want to submit a query something like this to the database:
SELECT DATE_FORMAT(i.timestamp,'%Y-%m') AS `month`
, SUM(i.price*i.qty) AS `total`
FROM order_items i
WHERE i.productID = 'foo'
AND i.timestamp >= '2013-01-01'
AND i.timestamp < '2013-01-01' + INTERVAL 12 MONTH
GROUP
BY DATE_FORMAT(i.timestamp,'%Y-%m')
(This assumes that the timestamp column is MySQL datatype TIMESTAMP, DATETIME or DATE)
Using the deprecated mysql_ interface, you want to avoid SQL Injection vulnerabilities using the mysql_real_escape_string function. (A better option would be to use the mysqli or PDO interface, and use a prepared statement with bind placeholders.)
We want the predicates on the timestamp to be on the BARE column, so MySQL can make use of an available suitable index for a range scan operation, rather than requiring a full scan of every row in the table.
We also want to use the power of the server to quickly derive a total, and return just the total, rather than retrieving every flipping row, and processing each of those rows individually (RBAR = row by agonizing row)
The GROUP BY clause and the SUM() aggregate function are tailor made to suit this result.
With mysql_ interface, the query would look something like this:
$querytext = "
SELECT DATE_FORMAT(i.timestamp,'%Y-%m') AS `month`
, SUM(i.price*i.qty) AS `total`
FROM order_items i
WHERE i.productID = '" . mysql_real_escape_string($thisProductID) . "'
AND i.timestamp >= '" . mysql_real_escape_string($filterYear) . "-01-01'
AND i.timestamp < '" . mysql_real_escape_string($filterYear) . "-01-01' +
INTERVAL 12 MONTH
GROUP BY DATE_FORMAT(i.timestamp,'%Y-%m')";
# for debugging
#echo $querytext;

Show all results from database where mm/dd/yy date is "today" or greater

I am using HTML input type="date" to allow users to input appointment dates.
Now I want to query the database and show all appointments that are "today" and in the future.
Not dates that have already passed.
Here is my SQL Script
$today = date('d-m-Y');
$sql = "SELECT *
FROM `client1`
WHERE `client` = '$customer'
AND DATEDIFF('$today', `date`) >= 0
ORDER BY `id` DESC";
Can someone guide me as to how I can achieve this?
I have seen several directions online but I want to have the sorting done at the moment of query.
I have solved the issue!
My date() format was incorrect because HTML input type="date" inserts YYYY-MM-DD into the database =/
$today = date('d-m-Y');
should be
$today = date('Y-m-d');
My operator >= should have been <= to show today and future dates.
Thanks everyone for the help. I should have tried fixing it for 5 more minutes before posting.
Why are you using PHP to compare dates in the database? I assume its a date field so you can use MySQL to do it for you:
SELECT *
FROM `client1`
WHERE `client` = '$customer'
AND DATEDIFF(date_format(now(), '%Y/%m/%d'), `date`) >= 0
ORDER BY `id` DESC
None of the responses have specified sargable predicates. If you perform an operation on a column in the where clause, there is no discernible stopping point.
where ... some_function( some_field ) = some_constant_value ...
Even if some_field is indexed, a complete table scan must be performed because there is no way to know if the output of the operation is also ordered.
From my understanding the date column is in a sortable form -- either a date field or a string in lexically sortable format 'yyyy-mm-dd'. That being the case, don't do any operation on it.
where ... some_field >= now() ...
Thus the system can use the result of now() as a target value to find exactly where in the index to start looking. It knows it can ignore all the rows with indexed values "down" from the target value. It has to look only at rows with indexed values at or "up" from the target value. That is, it performs an index seek to the correct starting point and proceeds from there. This could mean totally bypassing many, many rows.
Or, to put it bluntly, ditch the datediff and do a direct comparison.

Issue of PHP and MySql function

while fetching data from MySQL for today's date, what should be preferred why
1) "select * from table1 where created_dt Like CURDATE()";
2) "select * from table1 where created_dt Like ".date(Y-m-d H:i:s);
will it make any difference in execution time of the script, If i use MySql function instead of php function or vice versa
will it make any difference in execution time of the script
Definitely NO.
The difference would be pretty negligable, though generating the date in SQL would probably be marginally faster.
You should not be using 'like' though, since that is for partial string comparisons, and you are using a date field (which, internally, will be an integer). You are also missing two sets of quotes for your php date example.
But most importantly, if you are using a datetime format for created_dt, and then attempting to match by date using date(created_dt) or any kind of string comparison, you will not be taking advantage of indexing, and are likely to cause a full table scan. You'd be better using:
select * from table1 where created_dt between CURDATE() and date_add(CURDATE(), interval 1 day);
Which can take advantage of a btree index on created_dt to make your query perform considerably faster and more efficiently.
It would be best to use option 1 - date value computed on the database server because:
MySQL doesn't need to convert the string value from the query to a date, since CURDATE retrieves a DATE value
the PHP date function parses the parameter and formates the date and concatenates the result to the query string, which is surely a more complex task then the mysql CURDATE function which has no parameters and simply retrieves the date

Categories