I'm just a beginner at mysql so in school we got task to do. It goes like this. Display / print 10% of all books from books in falling order. So i tried to use limit, but it doesn't work. What can i do? My code i've tried to use:
select title, price from book
order by price desc
limit (select count(*)*0.1 from book);
thank you for your answers!
limit values have to be hard-coded constants. You can't use variables on them, e.g. select ... limit #somevar is a syntax error. You also can't use sub-queries or other dynamic values either. So you're stuck with either fetching the row count ahead of time and stuff it into the query string as a "hard-coded" value:
$ten_percent = get_from_database('select count(*) / 10 from book');
$sql = "SELECT .... LIMIT $ten_percent";
Or you simply fetch everything and then abort your loop once you've reached 10%:
$sql = "SELECT ....";
$result = mysql_query($sql) or die(mysql_error());
$total_rows = mysql_num_rows($result);
$fetched = 0;
while($row = mysql_fetch_assoc()) {
$fetched++;
if ($fetched >= ($total_rows / 10)) {
break; // abort the loop at 10%
}
... do stuff with $row
}
Related
I want select X records from database (in PHP script), then sleep 60 seconds after continue the next 60 results...
SO:
SELECT * FROM TABLE WHERE A = 'B' LIMIT 60
SELECT SLEEP(60);
....
SELECT * FROM TABLE WHERE A = 'B' LIMIT X **where X is the next 60 results, then**
SELECT SLEEP(60);
AND etc...
How can I achievement this?
There is no such thing as "the next 60 records". SQL tables represent unordered sets. Without an order by, a SQL statement can return a result set in any order -- and even in different orders on different executions.
Hence, you first need something to guarantee the ordering . . . that is, an order by with keys that uniquely identify each row.
You can then use offset/limit to accomplish what you want. Or, you could put the code into a stored procedure and use a while loop. Or, you could do this on the application side.
In PHP:
<?php
// obtain the database connection, there's a heap of examples on the net, assuming you're using a library like mysqlite
$offset = 0;
while (true) {
if ($offset == 0) {
$res = $db->query('SELECT * FROM TABLE WHERE A = 'B' LIMIT 60');
} else {
$res = $db->query('SELECT * FROM TABLE WHERE A = 'B' LIMIT ' . $offset . ',60');
}
$rows = $db->fetch_assoc($res);
sleep(60);
if ($offset >= $some_arbitrary_number) {
break;
}
$offset += 60;
}
What you're doing is gradually incrementing the limit field by 60 until you reach a limit. The easiest way to do it is in a control while loop using true for the condition and break when you reach your invalid condition.
I have 2 mysql tables with 500.000 items
first with items price, items id, and ticket number
second with ticket_number, date of sales and total_price of ticket
by now i use this query
SELECT items.pri,ticket.date,items.crd,items.plu
FROM items ,ticket
WHERE
(items.crd = 25 OR items.crd = 30) AND items.SeqNbr = ticket.SeqNbr
then in php:
$val_1 = array();
$price1 = 0;
while($row = mysql_fetch_array($query))
{
if($row['crd'] == 25)
{
$prix = $row['pri'];
if($prix != $price1)
{
$val_1[] = array( (int)$row['date']*1000,(float)$row['pri']);
$price1 = $prix;
}
}
}
return:
[[1388552879000,1.519],[1389136505000,1.498],[1392420222000,1.514],[1394667334000,1.499],[1395373887000,1.478],[1395963467000,1.499],[1396649284000,1.52],[1397513210000,1.542],[1398384245000,1.556],[1399347974000,1.536],[1400910286000,1.553],[1403216692000,1.58],[1405029076000,1.563]]
goal is obtain an array with price change and date to build a charts of price fluctuation.
but with more than 500.000 records this is extremly slow (15 sec)
is there any possibilities to build mysql query that return the same array ?
Thanks
First you need to check where is the bottleneck, on the query or on the loop.
If it is on the query, check if you have the right index. If not, try adding index for the fields items.crd, items.SeqNbr and ticket.SeqNbr.
I wonder if there is a way to accomplish:
SELECT * FROM table
by using LIMIT and OFFSET like so:
SELECT * FROM table LIMIT all OFFSET 0
Can I write SQL statement using LIMIT and OFFSET but still getting ALL result?
* of course I can use an IF statement but I rather avoid it if possible
From the MySQL documentation:
To retrieve all rows from a certain offset up to the end of the result
set, you can use some large number for the second parameter. This
statement retrieves all rows from the 96th row to the last:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
So getting all rows might look as follows:
SELECT * FROM tbl LIMIT 0,18446744073709551615;
Yes, it is possible by providing NULL:
SELECT * FROM tab LIMIT NULL OFFSET NULL
db<>fiddle PostgreSQL demo
7.6. LIMIT and OFFSET
LIMIT ALL is the same as omitting the LIMIT clause, as is LIMIT with a NULL argument.
Snowflake LIMIT / FETCH
The values NULL, empty string (''), and $$$$ are also accepted and are treated as “unlimited”; this is useful primarily for connectors and drivers (such as the JDBC driver) if they receive an incomplete parameter list when dynamically binding parameters to a statement.
SELECT * FROM demo1 ORDER BY i LIMIT NULL OFFSET NULL;
SELECT * FROM demo1 ORDER BY i LIMIT '' OFFSET '';
SELECT * FROM demo1 ORDER BY i LIMIT $$$$ OFFSET $$$$;
I used this code in nodeJS with MySQL and it's run well, It's may help you.
Why you use it?
It's reliable because it's a string that will append with query.
If you want to set limit then you can put the limitation with the variable otherwise pass 0 with variable.
var noOfGroupShow=0; //0: all, rest according to number
if (noOfGroupShow == 0) {
noOfGroupShow = '';
}
else {
noOfGroupShow = ' LIMIT 0, '+noOfGroupShow;
}
var sqlGetUser = "SELECT `user_name`,`first_name`,`last_name`,`image`,`latitude`, `longitude`,`phone`,`gender`,`country`,`status_message`,`dob` as user_date_of_birth FROM `tb_user` WHERE `user_id`=?"+noOfGroupShow;
This may not be the best way to do it, but its the first that comes to mind...
SELECT * FROM myTable LIMIT 0,1000000
Replace 1000000 with some adequately large number that you know will always be larger than the total number of records in the table.
As the record will grow up, use mysql_num_rows to dynamically find total amount of records, instead of using some large number.
$cektotalrec=mysql_query("SELECT * FROM TABLE");
$numoffset=mysql_num_rows($cektotalrec);
$numlimit="0";
then:
$final="SELECT * FROM table ".$numlimit.", ".$numoffset"";
Maybe not the cleanest solution but setting limit to a very high number could work. Offset needs to be 0.
Why not use a IF statement where you add the limit and offset to the query as a statement is true?
You might receive an error if you set the limit to a very high number as defined by mysql doc. Thereofre, you should try to limit it 9999999999999, going higher can give you an error unless you set up server to go higher.
You might want to use LIMIT in a function, therefore it is not a bad idea. If you use it in a function, you might want it to be Limit All at one point and limit 1 at another point.
Below, I list an example where you might want your application to have no limit.
function get_navigation($select = "*", $from= "pages", $visible= 1, $subject_id = 2, $order_by = "position", $sort_by = "asc", $offset=0, $limit = 9551615){
global $connection;
$query = " SELECT {$select} ";
$query .= " FROM {$from} ";
$query .= " WHERE visible = {$visible} ";
$query .= " AND subject_id = {$subject_id} ";
$query .= " ORDER BY {$order_by} {$sort_by} ";
$query .= " LIMIT {$offset}, {$limit} ";
mysqli_query($connection, $query);
$navigation_set = mysqli_query($connection, $query);
confirm_query($navigation_set);
return $navigation_set;
}
define ("SELECT", "*");
define ("FROM", "pages");
define ("VISIBLE", 1);
define ("SUBJECT_ID", 3);
define ("ORDER_BY", "position");
define ("SORT_BY", "ASC");
define ("LIMIT", "0");
$navigation_set = get_navigation(SELECT, FROM, VISIBLE, SUBJECT_ID, ORDER_BY, SORT_BY);
I have a multi-table SQL query.
My need is: The query should I generate a single line by 'etablissement_id' ... and all information that I want to be back in the same query.
The problem is that this query is currently on a table where "establishment" may have "multiple photos" and suddenly, my query I currently generates several lines for the same id...
I want the following statement - LEFT JOINetablissementContenuMultimediaON etablissement.etablissement_id = etablissementContenuMultimedia.etablissementContenuMultimedia_etablissementId - only a single multimedia content is displayed. Is it possible to do this in the query below?
Here is the generated query.
SELECT DISTINCT `etablissement`. * , `etablissementContenuMultimedia`. * , `misEnAvant`. * , `quartier`. *
FROM `etablissement`
LEFT JOIN `etablissementContenuMultimedia` ON etablissement.etablissement_id = etablissementContenuMultimedia.etablissementContenuMultimedia_etablissementId
LEFT JOIN `misEnAvant` ON misEnAvant.misEnAvant_etablissementId = etablissement.etablissement_id
LEFT JOIN `quartier` ON quartier_id = etablissement_quartierId
WHERE (
misEnAvant_typeMisEnAvantId =1
AND (
misEnAvant_dateDebut <= CURRENT_DATE
AND CURRENT_DATE <= misEnAvant_dateFin
)
)
AND (
etablissement_isActive =1
)
ORDER BY `etablissement`.`etablissement_id` ASC
LIMIT 0 , 30
Here is the code used ZF
public function find (){
$db = Zend_Db_Table::getDefaultAdapter();
$oSelect = $db->select();
$oSelect->distinct()
->from('etablissement')
->joinLeft('etablissementContenuMultimedia', 'etablissement.etablissement_id = etablissementContenuMultimedia.etablissementContenuMultimedia_etablissementId')
->joinLeft('misEnAvant', 'misEnAvant.misEnAvant_etablissementId = etablissement.etablissement_id')
->joinLeft('quartier', 'quartier_id = etablissement_quartierId ')
->where ('misEnAvant_typeMisEnAvantId = 1 AND (misEnAvant_dateDebut <= CURRENT_DATE AND CURRENT_DATE <= misEnAvant_dateFin) ')
->where ('etablissement_isActive = 1')
->order(new Zend_Db_Expr('RAND()'));
$zSql = $oSelect->__toString();
if(isset($_GET['debug']) AND $_GET['debug'] == 1)
echo $zSql ;
//die();
$oResultEtablissement = $db->fetchAll($oSelect);
return $oResultEtablissement ;
}
Can you help me?
Sincerely,
If you are looking to have only one of the media displayed out of many regardless of which it may be then you can just add a limit to the query? After that you can tweak the query for ASCending or DESCending perhaps?
Is this query supposed to have images (or image as it were) for one establishment, or one image each for each active establishment? I see you have a limit 0,30 which means you're likely paginating....
If the result you want is a search for only one establishment, and the first image it comes to would work fine .. just use "limit 1" and you'll only get one result.
I took the time to redo the whole model of the database ... and now it works. There was no solution for a system as flawed
My Current query is:
SELECT DISTINCT DATE(vote_timestamp) AS Date, COUNT(*) AS TotalVotes FROM `votes`
WHERE vote_target_id='83031'
GROUP BY DATE(vote_timestamp) ORDER BY DATE(vote_timestamp) DESC LIMIT 30
(line breaks separated for readability)
Where vote_timestamp is a time for each "vote", Count(*) is the count for that day, and vote_target_id is the specific target of the vote.
Currently, this works for all days in which the target has at least one "vote", but I would like it to also return TotalVotes as 0 for days where there are no votes, rather than having no row at all.
Can this (and how?) be done in MySQL or PHP? (either is fine, as it is futher processed by PHP so either code can be used).
Thank you
The problem is how to generate records for days that have no rows. This SO question has some approaches.
Looking at that solution, it looks like for me it's much simpler to do this quick fix that sorta works.
$result = mysql_query($sql) or die('Internal Database Error');
if (mysql_num_rows($result) == 0) { return false; }
while($row = mysql_fetch_assoc( $result )) {
$votes[$row['Date']] = $row['TotalVotes'];
}
// fill 0s with php rather than using mysql
$dates = array_keys($votes);
for ($t = strtotime($dates[count($dates)-1]); $t <= time(); $t +=86400) {
$date = date('Y',$t).'-'.date('m',$t).'-'.date('d',$t);
if (!array_key_exists($date,$votes)) {
$votes[$date] = 0;
}
}
thanks though,