MYsql query and DB help - php

When trying to execute this query my mysql server cpu usage goes to 100% and the page just stalls. I setup an index on (Client_Code, Date_Time, Time_Stamp, Activity_Code, Employee_Name, ID_Transaction) it doesn't seem to help. What steps can I go about next to fix this issue? Also there is already one index on the database if that matters any. Thanks
> $sql = "SELECT m.Employee_Name, count(m.ID_Transaction)
>FROM ( SELECT DISTINCT Client_Code FROM Transaction)
> md JOIN Transaction m ON
> m.ID_Transaction = ( SELECT
> ID_Transaction FROM Transaction mi
> WHERE mi.Client_Code = md.Client_Code AND Date_Time=CURdate() AND Time_Stamp!='' AND
> Activity_Code!='000001'
> ORDER BY m.Employee_Name DESC, mi.Client_Code DESC, mi.Date_Time DESC,
> mi.ID_Transaction DESC LIMIT 1 )
> group by m.Employee_Name";

I've got a feeling it's due to that > sign next to the AND, what is the expression you're trying to make with that?

Could you express in plain English what results you're after with your query? I've got a feeling this query can be rewritten; that might fix your performance issue. A double join on itself might hurt performance badly.
Something like "the number of transactions per employee for today"?
If that's what you're after, please try this and refine from there:
select m.Employee_Name, count(m.ID_Transaction)
from Transaction m
where m.Date_time=CURdate()
and m.Time_Stamp != ''
and m.Activity_Code != '000001'
group by m.Employee_Name

I Could've sworn I had already posted my response here today....
Why not use a double GROUP BY? I think this is what you were looking for...
SELECT Employee_Name, count(ID_Transaction) FROM Transaction WHERE Date_time=CURdate() AND Time_Stamp != '' AND Activity_Code != '000001' GROUP BY Client_Code, Employee_Name

Related

How to adjust this query of research?

I need to adjust this query to do the search (like) in another column and another table.
See:
$query2 = "
select distinct(lances.codigo)
, datacompra
, horacompra
, cupom
from lances
, ".$tabelaCad."
where lances.idcliente = ".$tabelaCad.".id
and lances.datapgto = '0000-00-00'
and lances.horapgto = '00:00:00'
and (".$tabelaCad.".nome like '%".$cliente."%' or ".$tabelaCad.".usuario like '%".$cliente."%')
group
by lances.codigo
order
by lances.datacompra desc
, lances.horacompra desc
";
He currently searches only on: ".$tabelaCad.".nome and ".$tabelaCad.".usuario.
The variable $tabelaCad is the name of a table called cadastro, and the variable cliente is the one that receives the search POST.
I need her to look too in the column codigo from the table lances and in a new table called registro in the columns reg1 e reg2.
What would the query look like in this case? I have tried several ways and it does not work.
I am working with MySQL 5.7, still...
After a long discussion we found the last relation between the tables.
It is registro.reg1 to lances.codigo.
So the best way to solve the problem is to work with the inncer join.
You save unnecessary typing and can address the tables with aliases which is much more comfortable for writing procedures.
Here is my finished solution:
<?php
$query2 = "
select
distinct lc.codigo as codigo,
lc.datacompra as datacompra,
lc.horacompra as horacompra,
lc.cupom as cupom
from `lances` as lc
inner join `".$tabelaCad."` as ca on lc.idcliente = ca.id
inner join `registr` as ri on lc.codigo = ri.reg1
where lc.idcliente = ca.id
and lc.datapgto = '0000-00-00'
and lc.horapgto = '00:00:00'
and (ca.nome like '%".$cliente."%' or ca.usuario like '%".$cliente."%')
group
by lc.codigo
order
by lc.datacompra desc, lc.horacompra desc
";
?>
I put them in the selection because I do not know exactly what you intend to xD

How to make two $db->query from the same table with two different ORDER by column that each other stand independenty in one php page?

I want to make two blocktables in one page from the same DB table. The first blocktable I want to ORDER it by "posted_date" column, and the second I want to ORDER it by "numviews" column. I want the both blocktables not influence each other, altough they're on the same page. Is it possible?
I have made like this,
first block
$popresult = $db->query('
SELECT
t.id,
t.poster, f.id AS forum_id,
f.forum_name,
t.subject,
t.mainimg,
posted_date,
t.num_views
FROM '.$db->prefix.'forums
ORDER BY 'posted_date' DESC
LIMIT '.$numtopik.'', true)
or error('Tidak dapat mengambil topik populer', __FILE__, __LINE__, $db->error());
second block
$popresult = $db->query('
SELECT
t.id,
t.poster,
f.id AS forum_id,
f.forum_name,
t.subject,
t.mainimg,
posted_date,
t.num_views
FROM '.$db->prefix.'forums
ORDER BY t.num_views DESC
LIMIT '.$numtopik.'', true)
or error('Tidak dapat mengambil topik populer', __FILE__, __LINE__, $db->error());
but it still got error to fetch.
Can anybody help me please?
In your first query you don‘t order by the date, but use the value of $date in the LIMIT part of your query.
So your last part in your first query, should be more like:
[...] ORDER BY t.`yourDateColumnHere` DESC LIMIT '.$yourLimitVariableHere [...]
Hope that helps! If not, feel free to add a comment!

Prestashop product ORDER BY RAND optimization

I am using Prestashop Related Product PRO plugin that is really helpful when it comes to show some random products from the same category but it is using default Prestashop ORDER BY RAND method and when I enable this method to show 24 random products that product page idle loading time is from 4000ms to 7000ms because it is waiting for database to show some random products.
When I reduce it to 8 products it is 1500-2000ms but it is still too long when it comes to SEO score. I was looking for a solution in the pluging but I couldn't figure it out but I found this:
Presta 1.6.1.4 here. In classes\Category.php something about line 744 we have something like this:
$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) AS quantity'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
FROM `'._DB_PREFIX_.'category_product` cp
LEFT JOIN `'._DB_PREFIX_.'product` p
ON p.`id_product` = cp.`id_product`
'.Shop::addSqlAssociation('product', 'p').
(Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
'.Product::sqlStock('p', 0).'
LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
ON (product_shop.`id_category_default` = cl.`id_category`
AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
ON (p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
LEFT JOIN `'._DB_PREFIX_.'image_lang` il
ON (image_shop.`id_image` = il.`id_image`
AND il.`id_lang` = '.(int)$id_lang.')
LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
ON m.`id_manufacturer` = p.`id_manufacturer`
WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
AND cp.`id_category` = '.(int)$this->id
.($active ? ' AND product_shop.`active` = 1' : '')
.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');
if ($random === true) {
$sql .= ' ORDER BY RAND() LIMIT '.(int)$random_number_products;
} else {
$sql .= ' ORDER BY '.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).'
LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;
}
And if I am not wrong this is responsible for showing off products on categories pages (including some plugins as well). Really bad order by rand(). As You can see there is a line
if ($random === true) {
$sql .= ' ORDER BY RAND() LIMIT '.(int)$random_number_products;
}
and in my opinion this is the key when we can start some changes. I found an article about optimizing MySQL ORDER BY RAND queries with some really satisfying results. You can read them here
https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/
and here
http://jan.kneschke.de/projects/mysql/order-by-rand/ (in this case the results were just amazing)
But there is a case. My programming skills are limited to implement those methods into Prestashop: ( This is just way complicated for me so can someone help me with editing those lines with one of new methods. Can anyone with better experience and knowledge can help me? Or invent something which is better then those which I proposed?
Let's assume you want to present a choice of k = $random_number_products from within the set of all n rows in your prefix_product table. That means you're hoping to choose k / n of your rows randomly.
RAND() generates a pseudorandom number in the range [0,1]. So to implement k / n choice, you need RAND() <= k / n or, moving it to the integer comparison domain, n*RAND() <= k . If your application will fail in the case that your query chooses too few random rows, you need to boost up your k value to increase the probability of any row being chosen. Let's just say k+5 for good measure.
Then you need to add something to the end of the SELECT clause in your query, right after orderprice, like this:
SELECT...,
INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice,
(SELECT COUNT(*) FROM `'._DB_PREFIX_.'product`) * RAND() AS selector
...
This assigns a random selector between 0 and the COUNT(*) value to each row in the result set.
Finally, at the end of your query put this.
if ($random === true) {
$sql .= ' HAVING selector <= ', (5+$random_number_products);
$sql .= ' ORDER BY selector LIMIT '.(int)$random_number_products;
}
I think this will work.
HAVING chooses a subset of your rows. You need HAVING rather than WHERE for this particular application, because it refers to a generated column.
5+ overestimates the size of that subset slightly.
ORDER BY randomizes the order of the chosen rows.
LIMIT gets rid of any extra rows resulting from your overestimate.
I may have left in some syntax errors. If so, I beg your pardon.
ORDER BY RAND() LIMIT n is an especially smelly case of the nasty antipattern ORDER BY anything LIMIT n. It wastes server resources. It generates the entire result set (in server RAM or on disk if it doesn't fit in RAM), then sorts it into some kind of order, then returns a few rows, than discards the rest. The secret to good performance in these cases is to discard rows as early as possible, and to sort the smallest result set.
But it works. So if the query runs infrequently, just keep it. In your case the query runs frequently.
(Prestashop? ORDER BY RAND()? Really? When you get this working send them a bug report with your fix in place.)
Virtually all algorithms out there are O(N) or worse. In my blog on faster random searches, I link to them as 'not adequately fast', including jan's classic page. I present 5 cases; I don't know which can be applied to your situation:
Case: Consecutive AUTO_INCREMENT without gaps, 1 row returned
Case: Consecutive AUTO_INCREMENT without gaps, 10 rows
Case: AUTO_INCREMENT with gaps, 1 row returned
Case: Extra FLOAT column for randomizing
Case: UUID or MD5 column
All cases run faster than a full table scan.

how to solve this mysql query

I have 3 mysql tables
user(u_id(p),name),
team(t_id(p),u_id(f),t_name,t_money,days_money) and
history(t_id(f),day,d_money).
Now I have to display leaderboard using php.
I tried this.
SELECT t_id FROM team;
got result.
then,
in for loop
foreach($tid_all as $tid)
{
$que = $db_con->prepare("SELECT d_money, t_name FROM team, history WHERE t_id= '".$tid['t_id']."' && day='1'");
$que->execute();
while($info = $que->fetch(PDO::FETCH_NUM))
{
echo "<tr>";
echo "<td>".$info[0]."</td>";
echo "<td>".$info[1]."</td>";
echo "</tr>";
}
}
but it didnt work. any solution?
Solution 1:
i tried this and it worked.
`SELECT d_money, t_name FROM team, history WHERE history.t_id=$tid['t_id'] AND team.t_id=history.t_id`
is it correct way or not?
thanks everyone for help.
Question : is it possible to order the result table by d_money? i want it in descending order.
Replace && with AND.Try like this :
"SELECT d_money, t_name FROM team, history WHERE t_id= '".$tid['t_id']."' AND day='1' order by d_money DESC "
There is no && in MySQL Query. Replace that with AND Operator on your query.
Since you want to get the data from the two tables, then JOIN the two tables instead of doing that with a loop:
SELECT
h.d_money,
t.t_name
FROM team AS t
INNER JOIN history AS h ON t.t_id = h.t_id;
Run this single query once and you will get what you want. You can also add a WHERE clause at the end of it the way you did in your query.
try this
SELECT d_money, t_name FROM team, history WHERE team.t_id= '".$tid['t_id']."' AND history.t_id= '".$tid['t_id']."' && day='1'
Can you replace
WHERE t_id= '".$tid."' AND day='1'
instead of
WHERE t_id= '".$tid['t_id']."' && day='1'

Best way to sum and seperate by date in MYSQL with/witout php

Hi i have such table information:
what i want to do with php with while or just in mysql, is to SUM (time_used) of the rows with status 44 until its reached row with status 55. after that it should begin from start with new summing.
first query should return 37, second 76 (keep in mind it should be universal, for unlimited occurrences of 55 status row)
i thought of a way with time/date filtering and have this:
select sum(time_used) as sumed
from timelog
where start_time > (select end_time from timelog where (status='55')
ORDER BY id DESC LIMIT 1) ORDER BY id DESC
but this works only for last combination of 44 and 55
i know i will need two way filtering( < end_time and > end_time) so it will work for all cases, but cant think of a way to do it in php
can anyone help me?
EDIT:
sqlfiddle whoever want it:
http://sqlfiddle.com/#!2/33820/2/0
There are two ways to do it: Plain SQL or PHP. If you treat thousands of rows, it may be interresting to choose between the two by testing performance.
Plain SQL
select project_id, task_id, user_id, sum(time_used) as time_used,
min(start_time) as start_time, max(end_time) as end_time, max(comment) as comment from
(select t.id, t.project_id, t.task_id, t.user_id, t.time_used,
count(t2.id) as count55, t.start_time, t.end_time, t.comment
from timelog t
left join timelog t2 on t.id>t2.id and t2.status=55 and t.task_id=t2.task_id
group by t.id) as t
group by count55;
I assume here that a task can belong to one user only
SQL and PHP
$link = mysqli_connect( ... );
$query = "select id, project_id, task_id, user_id, time_used, start_time, end_time, status
from timelog order by id";
$result = mysqli_query($link, $query);
$table = array();
$time_used = 0;
$start_sum = true;
$i = 0;
while($row = mysqli_fetch_assoc ($result)){
if($start_sum){
$table[$i] = $row;
$start_sum = false;
} else {
$table[$i]['time_used'] += $row['time_used'];
$table[$i]['end_time'] += $row['end_time'];
}
if($row['state'] == 55){
$i++;
$start_sum = true;
}
}
If two tasks can run in simultaneously, solution 1 will work, but solution 2 will need to be adapted in order to take this in account.
here is my intepretation:
http://sqlfiddle.com/#!2/33820/45
set #n=0;
select project_id, task_id, user_id,sum(time_used) from (
SELECT time_used,project_id, task_id, user_id,
#n:=if(status=55,#n+1,#n),
if(status=55,-1,#n) as grouper FROM timelog
) as t
where grouper>-1
group by grouper;
I'm neither a php nor MySQL programmer, but I can explain the logic you want to follow. You can then code it.
First, query your db and return the results to php.
Next, set two sum variables to 0.
Start looping through your query results. Increment the first sum variable until you reach the first row that has status 55. Once you do, start incrementing the second variable.
The tricky part will be to sort your query by the row number of the table. Here is a link that will help you with that part.

Categories