Combination of two SQL queries - mysql

I have two separate SQL queries that I would like to combine to a single one if possible.
Query #1 yields all entries from a table in random order
Query #2 will afterwards check whether or not the result can be used
How can I achieve this in a single step directly in SQL?
Code:
// start with a query for all of the photos, returned in random order
$query = "
SELECT DISTINCT m.mediaID
, m.description
, m.path
, m.alwayson
, m.usecollfolder
, m.mediatypeID
FROM $media_table m
WHERE m.mediatypeID = 'photos'
ORDER BY RAND();
";
$result = mysql_query($query) or die ("$text[cannotexecutequery]: $query");
while( $imgrow = mysql_fetch_assoc( $result ) ) {
// if the picture is alwayson or we are allowing living to be displayed,
// we don't need to bother
// with any further checking
if ($imgrow[alwayson] || $allow_living_db ) {
break;
// otherwise, let's check for living
} else {
// this query will return rows of personIDs on the photo that are living
$query = "
SELECT l.personID
FROM $medialinks_table l
JOIN $people_table p ON l.personID = p.personID
WHERE l.mediaID = $imgrow[mediaID]
AND p.living = 1
";
$presult = mysql_query($query) or die ("$text[cannotexecutequery]: $query");
$rows = mysql_num_rows( $presult );
mysql_free_result( $presult );
// if no rows are returned, there are no living on the photo, so let's display it
if ($rows == 0) {
break;
}
}

SELECT DISTINCT m.mediaID
, m.description
, m.path
, m.alwayson
, m.usecollfolder
, m.mediatypeID
, l.personID
FROM $media_table m
JOIN $medialinks_table l
ON l.mediaID = m.mediaID
JOIN $people_table p
ON l.personID = p.personID
WHERE m.mediatypeID = 'photos'
AND p.living = 1
ORDER
BY RAND();

Related

How to retrieve 500k records DB data faster?

I have two tables T1 1 000 records and T2 with 500 000 records. I have a query where I run a join between them and fetch data by performing some aggregations. My page seems to be loading slow. Are there any approaches to make this query faster?
I have created indexes on columns for which aggregations are being performed. I think it is a generic statement.
$query = Mymodel::selectRaw("supplier_data.name as distributor,supplier_data.name as name, supplier_data.group_id as group_id, supplier_data.pay,supplier_data.group_id as submitted_group_plan,supplier_data.group_id as group_id_string,
(SELECT sum(t.net_claim) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as trans_number,
(SELECT sum(t.claim) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as claim,
(SELECT sum(t.reversed) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as reversed,
(SELECT sum(t.reversal) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as reversal
");
I don't see the need of this too complex/repeated with same clauses and multiple sub selects for same table which can done using a single left join
SELECT
s.name AS distributor,
s.name AS name,
s.group_id AS group_id,
s.pay,
s.group_id AS submitted_group_plan,
s.group_id AS group_id_string,
SUM(t.net_claim) AS trans_number,
SUM(t.claim) AS claim,
SUM(t.reversed) reversed,
SUM(t.reversal) reversal
FROM
supplier_data s
LEFT JOIN transactions_data_new t
ON `t`.`member_id` = s.`group_id`
AND (
(
t.`submit_date` >= '$date_from'
AND t.`submit_date` <= '$date_to'
)
OR (
t.claim_status IS NULL
AND t.submit_date IS NULL
)
)
GROUP BY s.name,
s.group_id,
s.pay
As I understand it the chunk() method is for use when you need to work with a large dataset and take an action on that data chunk by chunk.
From your question, it sounds like you're performing a query then returning the data as JSON so to me, it doesn't sound like you're taking an action on your dataset that requires chunking.
If you want to break up the returned JSON data you should be instead looking at pagination.
You could apply pagination to your query like so:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->paginate();
You can specify the size of each set by passing a number to the paginate method:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->paginate(25);
If I've misunderstood and you did actually want to do the chunking, I believe you could do the following:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->chunk(50, function($inspectors) {
foreach ($inspectors as $inspector) {
// apply some action to the chunked results here
}
});
Also, if you're returning an eloquent object it will be automatically cast to json so you don't need to perform json_encode() as far as I'm aware.

Comparing two queries while executing

$query=mysql_query("SELECTcom_jobcard.job_card_num,process.process_name,employee.emp_name,employee.emp_code ,SUM(worked_qty) FROMcom_jobcard
INNER JOIN timer_completed ON timer_completed.job_card_id = com_jobcard.id
INNER JOIN process ON process.id = timer_completed.process_id
INNER JOIN employee ON employee.id = timer_completed.employee_id
AND job_card_id = ( SELECT id FROM com_jobcard WHERE job_card_num = 'JCID-1271742')
GROUP BY process.process_name,employee.emp_name ");
$query1 = mysql_query("SELECT com_jobcard.job_card_num,process.process_name,employee.emp_name,employee.emp_code,SUM(qc.rework_qty),qc.report_date,qc.id FROM qc
INNER JOIN com_jobcard ON qc.job_card_id = com_jobcard.id
INNER JOIN process ON process.id = qc.process_id
INNER JOIN qc_employees ON qc_employees.qc_id = qc.id
INNER JOIN employee ON employee.id = qc_employees.employee_id
AND qc_employees.qc_id = (SELECT qc.id
FROM qc
INNER JOIN com_jobcard ON qc.job_card_id = com_jobcard.id
AND com_jobcard.job_card_num = 'JCID-1271742')
GROUP BY process.process_name,employee.emp_name");
while ($row = mysql_fetch_array($query)) {
$row1 = mysql_fetch_array($query1);
if( ($row[1] == $row1[1]) && ($row[3] == $row1[3] ))
{
echo $row1[0] .$row1[1] .$row1[2] .$row1[3] .$row1[4];
}
}
Dear friends I am executing 2 queries simultaneously but I would like to compare both the result sets when $row[1] == $row1[1]) && ($row[3] == $row1[3] the condition is satisfied then it has to return the result but as if now it returns nothing could any one suggest me how to compare the result set of both the queries , Instead of using IF I have also used While statement , though I didn't recieve the result .
Please help me!
Thank you!
Use it like this
$row1 = mysql_fetch_array($query1);
while ($row = mysql_fetch_array($query)) {
while($row1) {
if( ($row['process_name'] == $row1['process_name']) && ($row['emp_name'] == $row1['emp_name'] ))
{
echo $row1['job_card_num'] .$row1['process_name'] .$row1['emp_name'] .$row1['emp_code'] .$row1['sum_qty'];
}
}
}
Because you have used $row[1] $row1[1] which has no value.
I ahev used alias vakue for SUM(qc.rework_qty) in your query as sum_qty

LEFT JOIN with exceptions

Here's my current query:
$q = "SELECT u.uid,CONCAT_WS(' ', u.first_name, u.last_name) name, CASE WHEN t.name IS NULL THEN 0 ELSE t.name END AS teamname ";
$q .= "FROM {$users} ";
$q .= "LEFT JOIN {$schedule} ON u.uid = s.uid ";
$q .= "LEFT JOIN {$products} ON p.admitting_id = u.uid ";
$q .= "LEFT JOIN {$teams} ON t.id = s.team ";
$q .= "WHERE (u.uid = {$current_user_id} AND u.roles = 'hoa') OR ";
$q .= "(p.id={$pid} AND p.admitting_id != 0) OR ";
$q .= "(t.admitting = 1 AND s.inactive != 1 AND s.role = 'hoa' AND (s.date = '{$today}' OR (s.date = '{$yesterday}' AND t.overnight = 1))) ";
$q .= "ORDER BY u.last_name,u.first_name,t.name";
What I need to get is:
Current User, if Current User has role hoa
User where uid matches admitting_id from products table
All users with role hoa who are scheduled today or were scheduled yesterday on an overnight shift. With those scheduled users, I need the names of the team they were/are scheduled with. Duplicate uids is good because I need all the different team names if they were scheduled on multiple teams.
What I don't need to get is:
Team name for options 1 and 2 above.
What I'm getting is:
Everything perfect for #3 above.
All possible team names for #1 and #2 above, whereas I want the team names to be 0 if they're not on the schedule.
I could split this up into three queries but that's not preferable.
Sometimes formatting the query out a bit helps visualise. It doesn't need to become three queries, I agree.
Can you provide some sample schema and data, ideally both in the question description and on something like sqlfiddle for us to play with?
It's hard to visualise your structure and data, but I'm speculating the issue is every record in users table is joining to schedule with the on clause you've used.
You could move the logic of condition 3 into the on clause (it's a left join, so nothing else will break) or duplicate it in the CASE statement in the SELECT:
$q = <<<SQL
SELECT
u.uid,
CONCAT_WS(' ', u.first_name, u.last_name) name,
IF(
WHEN t.name IS NULL THEN
0
ELSE
t.name
END AS teamname
FROM {$users} AS u
LEFT JOIN {$schedule} AS s ON (u.uid = s.uid)
LEFT JOIN {$products} AS p ON (p.admitting_id = u.uid)
LEFT JOIN {$teams} AS t ON
(
t.id = s.team AND
t.admitting = 1 AND
s.inactive != 1 AND
s.role = 'hoa' AND
(
s.date = '{$today}'
OR
(
s.date = '{$yesterday}' AND
t.overnight = 1
)
)
)
WHERE
( -- 1: Current User, if Current User has role hoa
u.uid = {$current_user_id} AND
u.roles = 'hoa'
)
OR
( -- 2: User where uid matches admitting_id from products table
p.id={$pid} AND
p.admitting_id != 0
)
OR
t.name IS NOT NULL
ORDER BY
u.last_name,
u.first_name,
t.name
SQL;
I'm absolutely not certain that'll fix your problem without something real to play with... Happy to continue looking if you can provide a working example sandpit.

MYSQL multiply if?

I have a query that looks like this:
//execute the SQL query and return records
$result = mysql_query("SELECT SUM(ps_order_detail.product_weight) as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
");
//fetch tha data from the database
while ($row = mysql_fetch_array($result))
{
echo '<font size="3">';
echo " Namn: ".$row{'firstname'}. "";
echo " Provision: ".$row{'total_provision'}. "";
echo " Abonnemang: ".$row{'antal_ordrar'}. "";
echo '<br>';
echo '</font size>';
}
It works fine but what i wana do is if the result "antal_ordrar" is larger than say 50 i wana multiply the result "total_provision" with 1,2 (add an extra 20% to the result)
Im new on mysql and are kinda stuck. Any ideas?
SELECT SUM(ps_order_detail.product_weight) *
IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 ) AS total_provision,
COUNT(ps_order_detail.id_order_detail) AS antal_ordrar, ...
First, wrap this in a subquery:
SELECT
-- use the if statement
IF( antal_ordrar > 50, total_provision * 1.2, total_provision ),
antal_ordrar,
firstname
FROM
-- create a subquery so you can reuse the data.
( SELECT SUM(ps_order_detail.product_weight) as total_provision,
COUNT(ps_order_detail.id_order_detail) as antal_ordrar,
ps_customer.firstname as firstname
FROM ps_order_detail
-- are you sure you need this many joins?
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
-- group by normally uses the 'having' keyword.
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE())
AND (ps_order_history.id_order_state) = '4'
OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC )
-- an alias for your subquery so you can treat it like a table.
tbl;
Just noticed this. You're using braces when you mean brackets: $row{'total_provision'} should be $row['total_provision'].
Try to add to select
if (antal_ordrar > 50, total_provision * 1.2, total_provision) as total_provision

MYSQL Limit results

I've almost done with my query, but there is still one last issue to resolve. My query looks like this:
//execute the SQL query and return records
$result = mysql_query("SELECT SUM(ps_order_detail.product_weight) * IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 )
as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
");
echo "<br>";
echo ("<img src=chart.php>");
echo "<br>";
echo ("<img src=chart_prov.php>");
//fetch tha data from the database
while ($row = mysql_fetch_array($result))
{
echo '<font size="3">';
echo " Namn: ".$row{'firstname'}. "";
echo " Provision: ".$row{'total_provision'}. "";
echo " Abonnemang: ".$row{'antal_ordrar'}. "";
echo '<br>';
echo '</font size>';
}
This part:
AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13'
causes the result to be displayed if the state of orders is either 4 or 13. The problem is that in the backend I can put it in those states many times, so if I'm not careful when updating orders, it will add the results more than one time.
Is it a way to limit that funktion to just handle latest update (have date_add in same table) or limit by 1?
Try to use
SELECT SUM(ps_order_detail.product_weight) * IF( COUNT(ps_order_detail.id_order_detail) > 50, 1.2, 1 )
as total_provision, COUNT(ps_order_detail.id_order_detail) as antal_ordrar, ps_customer.firstname
FROM ps_order_detail
JOIN ps_orders ON ps_order_detail.id_order = ps_orders.id_order
JOIN ps_order_history ON ps_orders.id_order = ps_order_history.id_order
JOIN ps_customer ON ps_orders.id_customer = ps_customer.id_customer
WHERE ps_order_history.id = (select ps_order_history.id from ps_order_history where ps_orders.id_order = ps_order_history.id_order and MONTH(ps_order_history.date_add) = MONTH(CURDATE()) AND (ps_order_history.id_order_state) = '4' OR (ps_order_history.id_order_state) = '13' order by ps_order_history.date_add desc limit 1)
GROUP BY ps_orders.id_customer
ORDER BY SUM(ps_order_detail.product_weight) DESC
Maybe it helps.