I have used this to get Data
SELECT customers.*, COUNT(invoice.payment_status) AS pending_invoices,sum(invoice.total ) AS total_pending_amount
FROM customers JOIN invoice ON (invoice.customer_id = customers.id)
WHERE invoice.payment_status = 'P' AND invoice.status = 'A' AND payment_followup_date IS NOT NULL AND payment_followup_date <= '2022-03-24 23:59'
GROUP BY invoice.customer_id
ORDER By payment_followup_date DESC
Now I am looking for a Query to perform an update on customers to add the current DateTime into payment_payment_followup_date and payment status = P for those customers who have more than 3 pending invoices
Try this:
UPDATE customers c
INNER JOIN (
SELECT
customer_id, COUNT(payment_status) pending_invoices
FROM invoice
WHERE payment_status = 'P' AND status = 'A'
GROUP BY customer_id
HAVING COUNT(payment_status) > 3
) i ON c.customer_id = i.customer_id
SET c.payment_payment_followup_date = CURRENT_TIMESTAMP()
c.payment_status = 'P'
WHERE c.payment_followup_date IS NOT NULL
AND c.payment_followup_date <= '2022-03-24 23:59'
Related
I would like to optimize my database query but I am not sure how to do this.
I want to get a list of stores' products opinions, ordered by opinion dates (from newest to oldest ones), but the products need to be unique.
For example, there are 3 users: U1, U2, U3.
There are 2 stores in the city:
S1 (with products P11, P12, P13, P14)
S2 (with products P21, P22, P23, P24)
Users added some opinions (the newest on the top, the oldest on the bottom):
U1: P22
U1: P13
U2: P21
U3: P13
U2: P23
U1: P23
What I want to achieve is:
U1: P22
U1: P13
U2: P21
U2: P23
The query I created is very long and a bit complicated. Could I simplify it somehow?
$sql_query = "
SELECT a.*
, b.name AS 'store_name'
, b.city AS 'store_city'
, c.name AS 'product_name'
FROM `app_products_opinion` AS a
JOIN `app_products_stores` AS b
ON a.store_ID = b.ID
JOIN `app_products` AS c
ON a.product_ID = c.ID
WHERE a.created_on IN
(
SELECT max(created_on) as created_on
FROM app_products_opinion
WHERE show_on_list='1' AND (added_by='".$_SESSION["CMSUserID"]."' OR status = '1')
GROUP by product_ID
ORDER by created_on DESC
)
AND a.show_on_list='1'
AND a.store_ID='".$id_store['ID']."' $addtosql
AND a.photo != ''
AND (a.added_by='".$_SESSION["CMSUserID"]."' OR a.status='1')
ORDER BY a.created_on DESC
";
You could try grouping by product_id and also joining by product_ID and date
(simplified code)
SELECT a.user_id, a.product_ID
from app_products_opinion a
INNER JOIN (
SELECT product_ID, max(created_on) as created_on
FROM app_products_opinion
WHERE show_on_list='1' AND (added_by='".$_SESSION["CMSUserID"]."' OR status = '1')
GROUP by product_ID
ORDER by created_on DESC
) t on a.created_on = t.created_on
AND a.product_ID = t.product_ID
I don't know if you think it's simpler (and ignoring, $addtosql) but you could do this...
SELECT a.*
, b.name AS 'store_name'
, b.city AS 'store_city'
, c.name AS 'product_name'
FROM `app_products_opinion` AS a
JOIN `app_products_stores` AS b
ON a.store_ID = b.ID
JOIN `app_products` AS c
ON a.product_ID = c.ID
JOIN
(
SELECT product_id
, max(created_on) created_on
FROM app_products_opinion
WHERE show_on_list = 1
AND (added_by = 'M' OR status = 1)
GROUP
by product_ID
) x
ON a.created_on = x.created_on
AND a.product_id = x.product_id
AND a.show_on_list = 1
AND a.store_ID = 'N'
AND a.photo != ''
AND (a.added_by = 'Z' OR a.status = 1)
I'm writing code for the production report.
I had written this query
SELECT
P.*,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_prod,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_dispatched,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production_dispatched,
C.name AS category_name
FROM
products P
INNER JOIN category C ON
C.id = P.category
This query is working but as I have too many records in all tables it takes too much time.
also, I need only records where before_prod, before_dispatched, production, production_dispatched all these subquery results should be greater than 0.
I tried to use having clause but it also takes too much time.
I have also tried php for loop, * LOGIC: first all products than in for loop its production. but it was much slower.*
How can I optimize my query?
You can use join instead and select case to sum your data that matches your conditions.
select p.*, t.*
from products p
inner join (
select t2.id, sum(case when create_date < '2019-11-01' then 1 else 0 end) as before_prod
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date < '2019-11-01' then 1 else 0 end) as before_dispatched
, sum(case when create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production_dispatched
from bales t1
inner join product t2 on t2.id= t1.product_id
inner join category t3 on t3.id = t2.category
where t1.TYPE in ('bale', 'bag')
group by t2.id) t
on t.id = p.id
This is my query and i need to check sub query column previousenddate in where condition without NULL.
SELECT pa.policy_id,
pa.person_id,
(
SELECT COUNT(pas.person_id)
FROM `package_assignments` pas
WHERE pas.person_id = pa.person_id
GROUP BY pas.person_id
) AS Member_Count,
pe.full_name,
pa.start_date,
pa.end_date,
(
SELECT p.end_date
FROM `package_assignments` p
WHERE p.person_id = pa.person_id
ORDER BY p.end_date DESC LIMIT 1,
1
) previousenddate
FROM `package_assignments` pa,
persons pe
WHERE end_date BETWEEN "2017-04-01"
AND "2017-04-30"
AND pa.person_id = pe.id
AND pa.rmhc_location = 5006
AND previousenddate > 1
I need to check the previousenddate column without Null For Eg:where previousenddate <> 'NULL'
I have a table with the following fields:
SELECT `sms_id`,
`u_id`,
`sender_id`,
`mobile_no`,
`message`,
`campaign_name`,
`status`,
`request_id`,
`route_id`,
`totalnumber`,
`msgcreadit`,
`date1`,
`deductbal`,
`submited`
FROM `send_sms`
WHERE 1
I want to select u_id whose status ="pending", but I want the latest pending status according to the [date1] date field and I also want the count of individual u_ids with status ="pending".
How can I do it?
In MySQL you can do:
SELECT s.*
FROM `send_sms` s
WHERE s.status = 'pending' AND
s.date1 = (SELECT MAX(s2.date1) FROM send_sms s2 WHERE s2.u_id = s.u_id and s2.status = 'pending');
Just another approach:
SELECT s.*
FROM `send_sms` s
LEFT JOIN `send_sms` s2
ON s.date1 < s2.date1
AND s2.u_id = s.u_id
AND s2.status = 'pending'
WHERE s.status = 'pending'
AND s2.status IS NULL
Here's the query:
SELECT h.idhour, h.`hour`, outnumber, count(*) as `count`, sum(talktime) as `duration`
FROM (
SELECT
`cdrs`.`dcustomer` AS `dcustomer`,
(CASE
WHEN (`cdrs`.`cnumber` like "02%") THEN '02'
WHEN (`cdrs`.`cnumber` like "05%") THEN '05'
END) AS `outnumber`,
FROM_UNIXTIME(`cdrs`.`start`) AS `start`,
(`cdrs`.`end` - `cdrs`.`start`) AS `duration`,
`cdrs`.`talktime` AS `talktime`
FROM `cdrs`
WHERE `cdrs`.`start` >= #_START and `cdrs`.`start` < #_END
AND `cdrs`.`dtype` = _LATIN1'external'
GROUP BY callid
) cdr
JOIN customers c ON c.id = cdr.dcustomer
LEFT JOIN hub.hours h ON HOUR(cdr.`start`) = h.idhour
WHERE (c.parent = _ID or cdr.dcustomer = _ID or c.parent IN
(SELECT id FROM customers WHERE parent = _ID))
GROUP BY h.idhour, cdr.outnumber
ORDER BY h.idhour;
The above query results skips the hours where there is no data, but I need to show all hours (00:00 to 23:00) with null or 0 values. How can I do this?
SELECT h.idhour
, h.hour
,IFNULL(outnumber,'') AS outnumber
,IFNULL(cdr2.duration,0) AS duration
,IFNULL(output_count,0) AS output_count
FROM hub.hours h
LEFT JOIN (
SELECT HOUR(start) AS start,outnumber, SUM(talktime) as duration ,COUNT(1) AS output_count
FROM
(
SELECT cdrs.dcustomer AS dcustomer
, (CASE WHEN (cdrs.cnumber like "02%") THEN '02' WHEN (cdrs.cnumber like "05%") THEN '05' END) AS outnumber
, FROM_UNIXTIME(cdrs.start) AS start
, (cdrs.end - cdrs.start) AS duration
, cdrs.talktime AS talktime
FROM cdrs cdrs
INNER JOIN customers c ON c.id = cdrs.dcustomer
WHERE cdrs.start >= #_START and cdrs.start < #_END AND cdrs.dtype = _LATIN1'external'
AND
(c.parent = _ID or cdrs.dcustomer = _ID or c.parent IN (SELECT id FROM customers WHERE parent = _ID))
GROUP BY callid
) cdr
GROUP BY HOUR(start),outnumber
) cdr2
ON cdr2.start = h.idhour
ORDER BY h.idhour
You need a table with all hours, nothing else.
Then use LEFT JOIN with the hours table on the "left" and your current query on the "right":
SELECT b.*
FROM hours h
LEFT JOIN ( ... ) b ON b.hr = h.hr
WHERE h.hr BETWEEN ... AND ...
ORDER BY hr;
Any missing hours will be NULLs in b.*.