This is my code:
select a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat,a.stok,a.laku, (a.stok-a.laku) as difference from (SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat, SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg, SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM barang, brg_laku
WHERE barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC) as a;
How to add where in that code?
where difference <= 3
Every time I write where, I get error message:
Unknown column 'difference' in where clause
SELECT a.id_brg,
a.nm_brg,
a.jen_sat,
a.nm_kat,
a.stok,
a.laku,
(a.stok-a.laku) as difference
FROM (
SELECT barang.id_brg,
barang.nm_brg,
jen_sat,
nm_kat,
SUM(IFNULL(stok_brg.stok, 0)) AS stok,
IFNULL(laku, 0) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg,
SUM(IFNULL( brg_laku.dibeli, 0 )) AS laku
FROM barang
INNER JOIN brg_laku
ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku
ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) as a
WHERE (a.stok-a.laku) <= 3;
Now, Can you use an alias in the WHERE clause in MySQL?
From the MySQL Manual:
It is not allowable to refer to a column alias in a WHERE clause
because the column value might not yet be determined when the WHERE
clause is executed. See Section B.1.5.4, “Problems with Column
Aliases”.
Try below :
Select * from (select a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat,a.stok,a.laku, (a.stok-a.laku) as difference from (SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat, SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg, SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM barang, brg_laku
WHERE barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC) as a;select a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat,a.stok,a.laku, (a.stok-a.laku) as difference from (SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat, SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg, SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM barang, brg_laku
WHERE barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC) as a)fq where difference <= 3
You can't reference a column alias inside the same SELECT you are declaring it. Either you filter by the column expression (a.stok-a.laku) or you nest it as a subquery and filter it in an outmost scope.
Filter by the column expression:
select
a.id_brg,
a.nm_brg,
a.jen_sat,
a.nm_kat,
a.stok,
a.laku,
(a.stok-a.laku) as difference
from
(SELECT
barang.id_brg,
barang.nm_brg,
jen_sat,
nm_kat,
SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT
barang.id_brg,
SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM
barang, brg_laku
WHERE
barang.id_brg = brg_laku.id_brg
GROUP BY
barang.id_brg ASC
) AS brg_laku
ON barang.id_brg = brg_laku.id_brg
GROUP BY
barang.id_brg ASC) as a
WHERE
a.stok-a.laku <= 3 -- Here!
Nest the subquery:
SELECT
X.*
FROM
(
select
a.id_brg,
a.nm_brg,
a.jen_sat,
a.nm_kat,
a.stok,
a.laku,
(a.stok-a.laku) as difference
from
(SELECT
barang.id_brg,
barang.nm_brg,
jen_sat,
nm_kat,
SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT
barang.id_brg,
SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM
barang, brg_laku
WHERE
barang.id_brg = brg_laku.id_brg
GROUP BY
barang.id_brg ASC
) AS brg_laku
ON barang.id_brg = brg_laku.id_brg
GROUP BY
barang.id_brg ASC) as a
) AS X
WHERE
X.difference <= 3 -- Here!
Use WHERE (a.stok-a.laku) <= 3 not the alias.
SELECT a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat,a.stok,a.laku, (a.stok-a.laku) difference FROM(SELECT B.id_brg, B.nm_brg, jen_sat, nm_kat, SUM( IFNULL(SB.stok, 0 )) stok, IFNULL(laku, 0) laku
FROM barang B
JOIN satuan S ON B.id_sat = S.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg SB ON B.id_brg = SB.id_brg
LEFT JOIN (SELECT B.id_brg, SUM( IFNULL(BL.dibeli, 0)) laku
FROM barang B
INNER JOIN brg_laku BL ON B.id_brg = BL.id_brg
WHERE (a.stok-a.laku) <= 3
GROUP BY B.id_brg ASC) brg_laku BL ON B.id_brg = BL.id_brg
GROUP BY B.id_brg ASC) a;
You have to first get the a.stok and a.laku , calculate the difference and then store it to a sql variable and use it then in a where clause. Because mysql doesn't calculate the difference first in the select case and then fetches the appropriate rows. You have to do this. I hope this help you
The documentation of the SELECT statement explains:
A select_expr can be given an alias using AS alias_name. The alias is used as the expression's column name and can be used in GROUP BY, ORDER BY, or HAVING clauses.
[...]
It is not permissible to refer to a column alias in a WHERE clause, because the column value might not yet be determined when the WHERE clause is executed.
See Section B.5.4.4, "Problems with Column Aliases".
The solution is simple: don't use the alias in the WHERE clause, use the aliased expression instead:
SELECT ... (a.stok-a.laku) as difference, ...
...
WHERE a.stok-a.laku <= 3
...
MySQL -- as with all other databases -- does not allow table aliases in the WHERE clause. However, MySQL extends the HAVING clause to allow such filtering. So, you can do:
SELECT a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat, a.stok, a.laku,
(a.stok - a.laku) as difference
FROM (SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat,
SUM(COALESCE(stok_brg.stok, 0 )) AS stok,
COALESCE( laku, 0 ) AS laku
FROM barang JOIN
satuan
ON barang.id_sat = satuan.id_sat JOIN
kategori
ON barang.id_kat = kategori.id_kat LEFT JOIN
stok_brg
ON barang.id_brg = stok_brg.id_brg LEFT JOIN
(SELECT brg_laku.id_brg, SUM(COALESCE(brg_laku.dibeli, 0)) AS laku
FROM brg_laku
GROUP BY brg_laku.id_brg
) brg_lak
ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg
) as a
HAVING difference <= 3;
Notes:
I prefer COALESCE() to IFNULL() because the former is the ANSI-standard function.
I simplified the last subquery. The JOIN seems unnecessary. (It might be under some circumstances, but I'm guessing it is not.)
You probably don't need the COALESCE()/IFNULL() for the SUM()s. I left them in, but the NULLs are ignored in aggregation functions.
Related
SELECT X.workorder_id,X.order_id FROM mr_workorder_data AS X
LEFT JOIN
(SELECT order_id, workorder_id, GROUP_CONCAT(trim_id SEPARATOR '|') AS trim_id_arr
FROM mr_workorder_data
WHERE order_id = X.order_id AND workorder_id =
X.workorder_id GROUP BY order_id)
WHERE X.data_type = 'Accessories' GROUP BY X.workorder_id
You have a left join ( subselect ) without an alias add (eg:) T at the end of the subquery ()
SELECT X.workorder_id,X.order_id
FROM mr_workorder_data AS X
LEFT JOIN ( SELECT order_id,workorder_id,
GROUP_CONCAT(trim_id SEPARATOR '|') AS trim_id_arr
FROM mr_workorder_data
WHERE order_id = X.order_id AND workorder_id = X.workorder_id
GROUP BY order_id ) T
WHERE X.data_type = 'Accessories'
GROUP BY X.workorder_id
This my code :
SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat, SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg, SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM barang, brg_laku
WHERE barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
Preview Of My Code:
the question is I want to make column stok - laku and make that result as column result can u guys get it sorry I was bad for my english so I don't know how to speak hope you guys can understand me Thanks
Looks like you want the difference between column stok and laku. If so try this:
select a.id_brg, a.nm_brg, a.jen_sat, a.nm_kat,a.stok,a.laku, (a.stok-a.laku) as difference
from (SELECT barang.id_brg, barang.nm_brg, jen_sat, nm_kat, SUM( IFNULL( stok_brg.stok, 0 ) ) AS stok, IFNULL( laku, 0 ) AS laku
FROM barang
JOIN satuan ON barang.id_sat = satuan.id_sat
JOIN kategori ON barang.id_kat = kategori.id_kat
LEFT JOIN stok_brg ON barang.id_brg = stok_brg.id_brg
LEFT JOIN (
SELECT barang.id_brg, SUM( IFNULL( brg_laku.dibeli, 0 ) ) AS laku
FROM barang, brg_laku
WHERE barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC
) AS brg_laku ON barang.id_brg = brg_laku.id_brg
GROUP BY barang.id_brg ASC) as a;
I am trying to optimize a SQL query and I would like some expert opinion on the best/fastest way to combine GROUP BY and ORDER BY
Basically I am trying to select the lowest price from a products table and group them by merchant name.
This was my original query:
select p.*, m.*, d.* from datafeeds as d, products as p left outer join meta as m on p.mykey = m.mykey where p.datafeed_id = d.id and (match(p.name) against ('+asics +"gel" -women*' in boolean mode)) and p.datafeed_id = '35' and p.is_custom = 0 group by d.merchant_name order by d.merchant_name limit 50
And the ORDER BY was not working, I was getting grouped products but not the ones with the lowest prices.
After reading other discussions i came up with an improved query:
SELECT p . * , m . * , d . *
FROM datafeeds AS d, products AS p
INNER JOIN (
SELECT MIN( display_price ) AS MinPrice
FROM products AS p
WHERE 1 =1
AND (
MATCH (
p.name
)
AGAINST (
'+asics +"gel" -women*'
IN BOOLEAN
MODE
)
)
AND p.datafeed_id = '35'
AND p.is_custom =0
GROUP BY merchant_name
) AS p2 ON p.display_price = p2.MinPrice
LEFT OUTER JOIN meta AS m ON p.mykey = m.mykey
WHERE p.datafeed_id = d.id
AND (
MATCH (
p.name
)
AGAINST (
'+asics +"gel" -women*'
IN BOOLEAN
MODE
)
)
AND p.datafeed_id = '35'
AND p.is_custom =0
GROUP BY d.merchant_name
ORDER BY d.merchant_name
LIMIT 50`
The query gets the correct results but it is quite slow.
Is there a better way to do it?
Thanks in advance
You could try this
SELECT p.*,
m.*,
d.*
FROM datafeeds AS d,
(
SELECT *
FROM products
WHERE 1 = 1
AND (
MATCH ( name ) against ( '+asics +"gel" -women*' IN boolean mode ) )
AND datafeed_id = '35'
AND is_custom =0
ORDER BY merchant_name,
display_price) AS p
LEFT OUTER JOIN meta AS m
ON p.mykey = m.mykey
WHERE p.datafeed_id = d.id
GROUP BY d.merchant_name
ORDER BY d.merchant_name
LIMIT 50
how do I get the max date value of a union tables? Whenever I use GROUP BY, I only get the max date value of the first table. So far, here's my code:
SELECT * FROM ((SELECT tc.id, tc.personnel_id, tpi.emp_status, tpi.firstname, tpi.lastname, tc.date_from, tc.date_to FROM tbl_contracts AS tc
JOIN (SELECT personnel_id, MAX(date_to) AS Maxdatetime
FROM tbl_contracts
GROUP BY personnel_id) AS r
ON tc.personnel_id = r.personnel_id AND tc.date_to = r.Maxdatetime
LEFT JOIN tbl_personnel_info AS tpi
ON tpi.id = tc.personnel_id
WHERE tpi.firstname LIKE CONCAT('%', '', '%')
AND tpi.lastname LIKE CONCAT('%', '', '%')
ORDER BY tc.date_to DESC)
UNION ALL
(SELECT tpss.id, tpss.personnel_id, tpi.emp_status, tpi.firstname, tpi.lastname, tpss.date_from, tpss.date_to
FROM tbl_personnel_sea_service AS tpss
JOIN (
SELECT personnel_id, MAX(date_to) AS Maxdatetime
FROM tbl_personnel_sea_service
GROUP BY personnel_id
) AS r
ON tpss.personnel_id = r.personnel_id AND tpss.date_to = r.Maxdatetime
LEFT JOIN tbl_personnel_info AS tpi
ON tpi.id = tpss.personnel_id
WHERE tpi.firstname LIKE CONCAT('%', '', '%')
AND tpi.lastname LIKE CONCAT('%', '', '%')
AND agency_name = 'UMMI'
ORDER BY tpss.date_to DESC)) AS tmain
GROUP BY tmain.personnel_id
The result is correct. However if I use GROUP BY tmain.personnel_id, sorting result is wrong. It's not getting the max date value of the second table
I'd suggest you take the group by over all the column and aggregate the date and finally order by date_to (or whichever column/s you need)-
SELECT personnel_id,
emp_status,
first_name,
lastname,
MIN(date_from) date_from,
MAX(date_to) date_to
FROM (
(SELECT tc.id,
tc.personnel_id,
tpi.emp_status,
tpi.firstname,
tpi.lastname,
tc.date_from,
tc.date_to
FROM tbl_contracts AS tc
JOIN
(SELECT personnel_id,
MAX(date_to) AS Maxdatetime
FROM tbl_contracts
GROUP BY personnel_id
) AS r
ON tc.personnel_id = r.personnel_id
AND tc.date_to = r.Maxdatetime
LEFT JOIN tbl_personnel_info AS tpi
ON tpi.id = tc.personnel_id
WHERE tpi.firstname LIKE CONCAT('%', '', '%')
AND tpi.lastname LIKE CONCAT('%', '', '%')
ORDER BY tc.date_to DESC
)
UNION ALL
(SELECT tpss.id,
tpss.personnel_id,
tpi.emp_status,
tpi.firstname,
tpi.lastname,
tpss.date_from,
tpss.date_to
FROM tbl_personnel_sea_service AS tpss
JOIN
(SELECT personnel_id,
MAX(date_to) AS Maxdatetime
FROM tbl_personnel_sea_service
GROUP BY personnel_id
) AS r
ON tpss.personnel_id = r.personnel_id
AND tpss.date_to = r.Maxdatetime
LEFT JOIN tbl_personnel_info AS tpi
ON tpi.id = tpss.personnel_id
WHERE tpi.firstname LIKE CONCAT('%', '', '%')
AND tpi.lastname LIKE CONCAT('%', '', '%')
AND agency_name = 'UMMI'
ORDER BY tpss.date_to DESC
)) AS tmain
GROUP BY personnel_id,
emp_status,
first_name,
lastname
ORDER BY date_to
Anyone can help me, I am a bit stuck.
I have this query which works like a charm
SELECT * ,
matches - falsepositives AS hits
FROM (
SELECT c. * ,
IFNULL( p.total, 0 ) AS matches,
(
SELECT COUNT( * )
FROM ci_falsepositives n
WHERE n.addressbook_id = c.reference
AND n.sanction_key
IN (
SELECT sanction_key
FROM ci_matched_sanctions
)
) AS falsepositives
FROM ci_address_book c
LEFT JOIN (
SELECT addressbook_id,
COUNT( match_id ) AS total
FROM ci_matched_sanctions
GROUP BY addressbook_id
) AS p
ON c.id = p.addressbook_id
) AS S
WHERE matches > 0
ORDER BY hits DESC
But I would like to change it to sort where HITS are more than 0, but it tells me it doesn't know hits... Is it because it's a calculation of 2 items?
You can't use an aliases column in a WHERE clause. You need to rewrite it:
SELECT * ,
matches - falsepositives AS hits
FROM (
SELECT c. * ,
IFNULL( p.total, 0 ) AS matches,
(
SELECT COUNT( * )
FROM ci_falsepositives n
WHERE n.addressbook_id = c.reference
AND n.sanction_key
IN (
SELECT sanction_key
FROM ci_matched_sanctions
)
) AS falsepositives
FROM ci_address_book c
LEFT JOIN (
SELECT addressbook_id,
COUNT( match_id ) AS total
FROM ci_matched_sanctions
GROUP BY addressbook_id
) AS p
ON c.id = p.addressbook_id
) AS S
WHERE matches - falsepositives > 0
ORDER BY hits DESC
Or use a subquery:
SELECT * FROM (
SELECT * ,
matches - falsepositives AS hits
FROM (
SELECT c. * ,
IFNULL( p.total, 0 ) AS matches,
(
SELECT COUNT( * )
FROM ci_falsepositives n
WHERE n.addressbook_id = c.reference
AND n.sanction_key
IN (
SELECT sanction_key
FROM ci_matched_sanctions
)
) AS falsepositives
FROM ci_address_book c
LEFT JOIN (
SELECT addressbook_id,
COUNT( match_id ) AS total
FROM ci_matched_sanctions
GROUP BY addressbook_id
) AS p
ON c.id = p.addressbook_id
) AS S
) AS S2
WHERE hits > 0
ORDER BY hits DESC