Help me guys, how to make my query faster
SELECT b.id_barang
, b.nama
, ( SELECT SUM(qty) FROM baru_kasir WHERE k.id_barang = b.id_barang GROUP BY b.id_barang LIMIT 1)
- ( SELECT SUM(qty) FROM barang_gdg_pesan WHERE barang_gdg_pesan.id_barang = b.id_barang GROUP BY b.id_barang LIMIT 1 ) AS STOCK
FROM baru_barang b
WHERE stts = 'AKTIF'
ORDER
BY b.nama ASC;
It will almost certainly be more efficient to JOIN to tables of the SUMs rather than running two subqueries for every row:
SELECT bb.id_barang,
bb.nama,
bk.qty - bgp.qty AS stock
FROM baru_barang bb
JOIN (SELECT id_barang, SUM(qty) AS qty
FROM baru_kasir
GROUP BY id_barang) bk ON bk.id_barang= bb.id_barang
JOIN (SELECT id_barang, SUM(qty) AS qty
FROM barang_gdg_pesan
GROUP BY id_barang) bgp ON bgp.id_barang = bb.id_barang
WHERE stts='AKTIF'
ORDER BY bb.nama ASC;
Ensuring that you have indexes on the id_barang columns in each table will also help performance.
Related
How can I sort the results of a subquery that's using a json aggregate?
If I had a schema like this:
CREATE TABLE plans( id integer NOT NULL, name character varying(255));
CREATE TABLE plan_items ( id integer NOT NULL, plan_id integer NOT NULL, expected_at date, status integer);
I'm aggregating the plan_items result on a json column through a subquery.
Like this:
SELECT
plans.id,
plans.name,
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols
)) AS plan_items_data
FROM
plans
INNER JOIN plan_items ON plan_items.plan_id = plans.id
GROUP BY
plans.id,
plans.name
ORDER BY plans.id;
The JSON aggregate is working as expected and give me the results that I need. Ok.
But I can't order the results.
I've tried:
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status ORDER BY plan_items.expected_at) pi_cols
)) AS plan_items_data
and also:
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols ORDER BY pi_cols.expected_at
)) AS plan_items_data
But none of these solved.
Any ideas?
As Abelisto suggests, just use a simple aggregate expression with ordering:
jsonb_agg(plan_items ORDER BY plan_items.expected_at) AS plan_items_data
Join the tables with the desirable sort order and use lateral join to select columns for jsonb_agg():
select s.plan_id id, name, jsonb_agg(pi_col)
from (
select p.id plan_id, p.name, pi.id, expected_at, status
from plans p
join plan_items pi
on p.id = pi.plan_id
order by p.id, expected_at
) s,
lateral (
select plan_id id, expected_at, status
) pi_col
group by 1, 2
order by 1;
The above query seems to be more natural and flexible (and a bit faster in most cases) than the one with a subquery in a select list. However for better performance you should also apply Abelisto's suggestion:
select s.plan_id id, name, json_agg(pi_col order by pi_col.expected_at)
from (
select p.id plan_id, p.name, pi.id, expected_at, status
from plans p
join plan_items pi
on p.id = pi.plan_id
) s,
lateral (
select plan_id id, expected_at, status
) pi_col
group by 1, 2
order by 1;
I currently have a query that gets every product_id FROM the receive_pallet TABLE. Along with every id it also gets the AVG of the date between when it is ordered/received (date_entered from the TABLE receive_pallet and date_ordered from the TABLE cs_po)
SELECT a.product_id, avg(a.date) AS AVG
FROM (SELECT DATEDIFF(date_entered,date_ordered) AS date,po_number_full, product_id
FROM cs_po,receive_pallet
WHERE cs_po.id = receive_pallet.po_number_full
ORDER BY cs_po.id DESC )a
GROUP BY a.product_id;
The result would be something like:
product_id AVG
00010005.01S 25.2500
00010005.04D 19.0000
00010010.01S 21.2680
00010020.02S 15.1250
00010040.04S 12.2400
00010080.20S 16.6667
This query works, but i would like to LIMIT it to AVG the last 5 shipments, not all of them. This is the query i made to do so,
SELECT a.product_id, avg(a.date) AS AVG
FROM (SELECT DATEDIFF(date_entered,date_ordered) AS date,po_number_full, product_id
FROM cs_po,receive_pallet
WHERE cs_po.id = receive_pallet.po_number_full
AND product_id IN (SELECT product_id , date_entered, date_ordered FROM receive_pallet LIMIT 0,5)
ORDER BY cs_po.id DESC
)a
GROUP BY a.product_id;
I get this error when i try to test it. [Err] 1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME sub query'
I know i need to replace the IN() clause with an INNER JOIN as LIMIT simply isn't supported in an IN() sub query, But i don't know where to start if i have two sub queries/where to add the join. Thanks.
Tale a look at this:
SELECT
a.product_id,
AVG(a.date) AS AVG
FROM (
SELECT
DATEDIFF(date_entered, date_ordered) AS date,
product_id
FROM
cs_po c
JOIN (
SELECT
date_entered,
product_id,
po_number_full
FROM
receive_pallet
ORDER BY
date_entered DESC
LIMIT 5
) r ON c.id = r.po_number_full
ORDER BY
c.id DESC
) a
GROUP BY
a.product_id
;
I simplified it a bit, but I think it works the way you want.
I'm not amazing at SQL and can't figure out how to do this. Here are the two queries I have at the moment.
SELECT TicketID_PK, SubProjectID_FK, ProjectID_FK, CustomerID_FK, TicketDate, TicketNumber,
SignOff, WorkOrder, ClientPO, TicketType, Description, Processed
FROM Tickets
INNER JOIN CustomersSubProjects ON Tickets.SubProjectID_FK = CustomersSubProjects.SubProjectID_PK
INNER JOIN CustomersProjects ON CustomersSubProjects.ProjectID_FK = CustomersProjects.ProjectID_PK
WHERE TicketID_PK = 1
SELECT ROUND(WCB+Vacation+Stat+UIC+CPP+Overhead,2) AS Total
FROM EmployeeFormula
WHERE EffectiveDate <= $TicketDate
ORDER BY EffectiveDate DESC LIMIT 1
I'm saving TicketDate as $TicketDate and using it in the second query, but I'm sure there is a way to combine the two queries to avoid this. Any help would be appreciated.
Edit: I need to select the EmployeeFormula Total (as shown in second query) by comparing the TicketDate column (in the Tickets table) to the EffectiveDate column. So the results should look like this:
TicketID_PK SubProjectID_FK ProjectID_FK CustomerID_FK TicketDate TicketNumber Total
1 1 1 1 2014-01-05 1-0501-00 30.78
Use like a subquery.
SELECT TicketID_PK, SubProjectID_FK, ProjectID_FK, CustomerID_FK, TicketDate, TicketNumber,
SignOff, WorkOrder, ClientPO, TicketType, Description, Processed, (SELECT ROUND(WCB+Vacation+Stat+UIC+CPP+Overhead,2) FROM EmployeeFormula WHERE EffectiveDate <= TicketDate ORDER BY EffectiveDate DESC LIMIT 1) AS Total
FROM Tickets
INNER JOIN CustomersSubProjects ON Tickets.SubProjectID_FK = CustomersSubProjects.SubProjectID_PK
INNER JOIN CustomersProjects ON CustomersSubProjects.ProjectID_FK = CustomersProjects.ProjectID_PK
WHERE TicketID_PK = 1
This query below is perfect in producing the result for horse_id = 1 ... but I want to do this for all horses in the database. Can anyone share with me how to tweak this query so I can do that?
SELECT figures.entry_id,
max(figures.beyer)
FROM
( SELECT hrdb_lines.horse_id,
hrdb_entries.entry_id,
hrdb_lines.beyer
FROM hrdb_entries
INNER JOIN hrdb_lines
ON hrdb_lines.horse_id = hrdb_entries.horse_id
WHERE hrdb_lines.horse_id = 1
ORDER BY hrdb_lines.line_date DESC
LIMIT 2
) as figures
Perhaps I'm doing it all wrong too.
I think the following would generate the desired results:
SELECT `entry_id`, `beyer`
FROM (SELECT hrdb_entries.entry_id,
MAX( hrdb_lines.beyer )
FROM hrdb_entries
INNER JOIN hrdb_lines
ON hrdb_lines.horse_id = hrdb_entries.horse_id
GROUP BY hrdb_lines.horse_id
ORDER BY hrdb_lines.line_date DESC
) AS figures
If I'm understanding your question, something like this should be close:
SELECT
figures.horse_id,
figures.entry_id,
max(figures.beyer)
FROM
(SELECT
hrdb_lines.horse_id,
hrdb_entries.entry_id,
hrdb_lines.beyer
FROM hrdb_entries
INNER JOIN hrdb_lines ON hrdb_lines.horse_id = hrdb_entries.horse_id
ORDER BY hrdb_lines.line_date DESC
) as figures
GROUP BY figures.horse_id
One option to limit the MAX to just the most recent 2 beyer fields is to add a row number to the results and only include rows 1 and 2.
SELECT
figures.horse_id,
figures.entry_id,
max(figures.beyer)
FROM
(SELECT
#rn:=if(#prev_horse_id=horse_id,#rn+1,1) rn,
hrdb_lines.horse_id,
hrdb_entries.entry_id,
hrdb_lines.beyer,
#prev_horse_id:=hrdb_lines.horse_id
FROM hrdb_entries
INNER JOIN hrdb_lines ON hrdb_lines.horse_id = hrdb_entries.horse_id
INNER JOIN (SELECT #rn:=0) r
ORDER BY hrdb_lines.horse_id, hrdb_lines.line_date DESC
) as figures
WHERE rn <= 2
GROUP BY figures.horse_id
As per my requirement i made the below query. Now it not working.
Query is:
SELECT *
FROM T_INV_DTL T
LEFT JOIN (
SELECT inv_dtl_id,
Employee_id AS emp_id,
GROUP_CONCAT(DISTINCT Employee_id) AS Employee_id
FROM T_INV_INVESTIGATOR
GROUP BY
inv_dtl_id
)TII
ON T.inv_dtl_id = TII.inv_dtl_id
JOIN T_INVESTIGATION TI
ON T.inv_id = TI.inv_id
LEFT JOIN (
SELECT inv_dtl_id
FROM T_INV_BILL
GROUP BY
inv_dtl_id
)TIB
ON T.inv_dtl_id = TIB.inv_dtl_id
JOIN T_Insurance_company TIC
ON TI.client_id = TIC.ins_cmp_id
WHERE 1 T.Report_dt != '0000-00-00'
AND (
T.inv_dtl_id NOT IN (SELECT inv_dtl_id
FROM T_INV_BILL TIBS
WHERE TIBS.inv_dtl_id NOT IN (SELECT
inv_dtl_id
FROM
T_INV_BILL
WHERE
Bill_submitted_dt =
'0000-00-00'))
)
ORDER BY
Allotment_dt DESC
LIMIT 20
Can anyone tells the problem and can you please modify to more efficient query(Suppose if we have more than 100 records, then we take the count for it for pagination it should be give faster).
T_INV_DTL is main table and it connect to others. So my probelm is each entry of this table T_INV_DTL has multtiple investigation bill in the table T_INV_BILL. Report_dt in the T_INV_DTL. So my outcome is that i need result if there’s a report date in T_INV_DTL and not atleast one bill date in T_INV_BILL.
I need the result with both if there’s a report date in T_INV_DTL and not atleast one bill date in T_INV_BILL(If all have entered the bill submitted date it does not need it).
While I admittedly don't know what issues you're having (please provide addl info), your query does look like it could be optimized.
Removing your Where criteria and adding to your Join should save 2 of your table scans:
SELECT *
FROM T_INV_DTL T
LEFT JOIN (
SELECT inv_dtl_id,
Employee_id AS emp_id,
GROUP_CONCAT(DISTINCT Employee_id) AS Employee_id
FROM T_INV_INVESTIGATOR
GROUP BY
inv_dtl_id
)TII
ON T.inv_dtl_id = TII.inv_dtl_id
JOIN T_INVESTIGATION TI
ON T.inv_id = TI.inv_id
LEFT JOIN (
SELECT inv_dtl_id
FROM T_INV_BILL
WHERE Bill_submitted_dt != '0000-00-00'
GROUP BY inv_dtl_id
)TIB
ON T.inv_dtl_id = TIB.inv_dtl_id
JOIN T_Insurance_company TIC
ON TI.client_id = TIC.ins_cmp_id
WHERE T.Report_dt != '0000-00-00'
AND TIB.inv_dtl_id IS NULL
ORDER BY
Allotment_dt DESC
LIMIT 20