Example data to sort:
xy3abc
y3bbc
z3bd
Sort order must be abc, bbc, bd regardless of what is before the numeral.
I tried:
SELECT
*,
LEAST(
if (Locate('0',fcccall) >0,Locate('0',fcccall),99),
if (Locate('1',fcccall) >0,Locate('1',fcccall),99),
if (Locate('2',fcccall) >0,Locate('2',fcccall),99),
if (Locate('3',fcccall) >0,Locate('3',fcccall),99),
if (Locate('4',fcccall) >0,Locate('4',fcccall),99),
if (Locate('5',fcccall) >0,Locate('5',fcccall),99),
if (Locate('6',fcccall) >0,Locate('6',fcccall),99),
if (Locate('7',fcccall) >0,Locate('7',fcccall),99),
if (Locate('8',fcccall) >0,Locate('8',fcccall),99),
if (Locate('9',fcccall) >0,Locate('9',fcccall),99)
) as locationPos,
SUBSTRING(fcccall,locationPos,3) as fccsuffix
FROM memberlist
ORDER BY locationPos, fccsuffix
but locationPos gives me an error on the substring function call
It's not possible to reference that expression by its alias locationPos, within another expression in the same SELECT list.
Replicating the entire expression would be the SQL way to do it. (Yes, it is ugly repeating that entire expression.)
Another (less performant) approach is to use your query (minus the fccsuffix expression) as an inline view. The outer query can reference the assigned locationPos alias as a column name.
As a simple example:
SELECT v.locationPos
FROM ( SELECT 'my really big expression' AS locationPos
FROM ...
) v
This approach of using an inline view ("derived table") can have some serious performance implications with large sets.
But for raw performance, repeating the expression is the way to go:
SELECT *
, LEAST(
if (Locate('0',fcccall) >0,Locate('0',fcccall),99),
if (Locate('1',fcccall) >0,Locate('1',fcccall),99),
if (Locate('2',fcccall) >0,Locate('2',fcccall),99),
if (Locate('3',fcccall) >0,Locate('3',fcccall),99),
if (Locate('4',fcccall) >0,Locate('4',fcccall),99),
if (Locate('5',fcccall) >0,Locate('5',fcccall),99),
if (Locate('6',fcccall) >0,Locate('6',fcccall),99),
if (Locate('7',fcccall) >0,Locate('7',fcccall),99),
if (Locate('8',fcccall) >0,Locate('8',fcccall),99),
if (Locate('9',fcccall) >0,Locate('9',fcccall),99)
) AS locationPos
, SUBSTRING(fcccall
, LEAST(
if (Locate('0',fcccall) >0,Locate('0',fcccall),99),
if (Locate('1',fcccall) >0,Locate('1',fcccall),99),
if (Locate('2',fcccall) >0,Locate('2',fcccall),99),
if (Locate('3',fcccall) >0,Locate('3',fcccall),99),
if (Locate('4',fcccall) >0,Locate('4',fcccall),99),
if (Locate('5',fcccall) >0,Locate('5',fcccall),99),
if (Locate('6',fcccall) >0,Locate('6',fcccall),99),
if (Locate('7',fcccall) >0,Locate('7',fcccall),99),
if (Locate('8',fcccall) >0,Locate('8',fcccall),99),
if (Locate('9',fcccall) >0,Locate('9',fcccall),99)
),3
) AS fccsuffix
FROM memberlist
ORDER BY locationPos, fccsuffix
Unfortunately, with MySQL, it's not possible to reference the result of the locationPos column within an expression in the same SELECT list.
For only one numeral I like:
SELECT *
FROM memberlist
ORDER BY SUBSTRING(fcccall,
LOCATE('0',fcccall)+
LOCATE('1',fcccall)+
LOCATE('2',fcccall)+
LOCATE('3',fcccall)+
LOCATE('4',fcccall)+
LOCATE('5',fcccall)+
LOCATE('6',fcccall)+
LOCATE('7',fcccall)+
LOCATE('8',fcccall)+
LOCATE('9',fcccall),3)
But the sensible approach is not to store two separate bits of information in one field.
Related
Hi I want to perform a calculation inside a SUM with my sql, but there is one SUM field that consist of other SUM fields. I get the General error: 1111 Invalid use of group function. What is the proper way of summing other sum fields in SQL?
I can't use the alias of other sum fields to perform the calculation because it says that the alias is unidentified.
This part is my problem
SUM((SUM(transactions.payable) + SUM(transactions.discount) ) - SUM(deliveries.delivery_fee) ) AS raw_sales
Thank you
Here is my SQL.
SELECT
MONTHNAME(transactions.date_transac) AS MONTH,
SUM(transactions.payable) AS total,
SUM(transactions.discount) AS discount,
SUM(deliveries.delivery_fee) AS delivery,
SUM(
(
SUM(transactions.payable) + SUM(transactions.discount)
) - SUM(deliveries.delivery_fee)
) AS raw_sales,
MONTH(transactions.date_transac) AS monthnum
FROM
`transactions`
LEFT JOIN `requisitions` ON `transactions`.`requisition_id` = `requisitions`.`id`
LEFT JOIN `transactions` AS `ct`
ON
`transactions`.`code` = `ct`.`charge_transaction_code`
LEFT JOIN `deliveries` ON `transactions`.`delivery_id` = `deliveries`.`id`
WHERE
`transactions`.`transaction_type` = Sale AND YEAR(`transactions`.`date_transac`) = 2020
GROUP BY
`month`
ORDER BY
`monthnum` ASC
enter image description here
You can't nest aggregate functions. Here, I suspect that you could move the arithmetics within the aggregate function rather than attempting to nest:
SUM(
transactions.payable
+ transactions.discount
- COALESCE(deliveries.delivery_fee, 0)
) AS raw_sales
delivery_fee comes from a left join table so it could be null, hence we use coalesce().
That said, I am quite suspicious about the logic of your query. I am wondering, for example, why transactions appears twice in the from clause. There are also missing quotes around literal string "Sale" in the WHERE clause. If you were to ask a legitimate question, including sample data, desired results, and an explanation of the purpose of the query, one might be able to suggests optimizations.
The query just worked, I haven't realized that it is no longer necessary to calculate all Sum fields. I just removed the external sum.
I'm new to MYSQL, and I'm trying to validate the number of data which have the same name from 2 column that occurs more than one time, which I already try to use 'having' statement in this case and it throws me an error like this
Error Code: 3593. You cannot use the window function 'count' in this context.'
below I include an image of what I'm trying to do
you can see there a column named "number_of_same_year" represent the "COUNT OVER PARTITION" output, which has numbers that logically could be validated. I only want to show where the numbers are above 1 (which means occur more than one time)
ps: I'm using MySQL in Windows 10
You cannot use having and a window function. You would want to instead do as follows
select * from (
select unit_name
,month(transaction_date)
,year(transaction_date) as year
,budget
,count(*) over(partition by unit_name,year(transaction_date)) as number_of_same_year
from sql_advertising.history_transaction
)x
where x.number_of_same_year >1
order by x.unit_name
SELECT {fieldset}
FROM {tableset}
WHERE {conditions-1}
GROUP BY {expression-1}
HAVING {conditions-2}
AND {expression-2} = COUNT({expression-3}) OVER ({window})
Window function is applied to output dataset, but HAVING alters it. So window function cannot be used in HAVING. The above code is invalid.
You may solve it by:
WITH `cte` AS ( SELECT {fieldset},
{expression-2} = COUNT({expression-3}) OVER ({window}) AS `criteria`
FROM {tableset}
WHERE {conditions-1}
GROUP BY {expression-1}
HAVING {conditions-2} )
SELECT {fieldset}
FROM `cte`
WHERE `criteria`
I have this table with some data that i am interested in. The table is called trades. basically, i want to select all data in that table but this conditions must hold.
trade_session_status="DONE"
(trade_prediction="up" AND trade_result="up" ) OR (trade_prediction="down" AND trade_result="down" )
I have written the whole query like this
select * from trades where trade_session_status="DONE" AND
(trade_prediction="up" AND trade_result="up" ) OR
(trade_prediction="down" AND trade_result="down" )
I want to get all data where trade_session_status is "DONE" and someone predicted up and the result indeed came to be up or someone who predicted down and the result came to be down.
The query returns some data without any error. Is my query expression correct?.
You need to add additional brackets:
select *
from trades
where trade_session_status="DONE"
AND ((trade_prediction="up" AND trade_result="up" )
OR (trade_prediction="down" AND trade_result="down" ))
Alternatively:
select *
from trades
where trade_session_status='DONE'
AND (trade_prediction, trade_result) IN (('up', 'up'),('down', 'down'))
I have a MySQL procedure that takes in 2 parameters par_DateFrom and par_DateTo
I'm getting a nasty error. I'm pretty sure that reusing alias TotalDaysOut to calculate TotalIncome is the culprit. How can I fix this elegantly?
Error 1247:
reference TotalDaysOutnot supported reference to group function
BEGIN
SELECT t.LicencePlate
,f.Make
,f.Model
,f.Year
,COUNT(t.LicencePlate) AS TotalTrx
,SUM(DATEDIFF(IF(checkedIn >par_DateTo, par_DateTo, checkedIn) ,IF(checkedOut <par_DateFrom, par_DateFrom, checkedOut))) AS TotalDaysOut
,SUM(t.Price* (SELECT TotalDaysOut)) AS TotalIncome
FROM TRANSACTIONS t
INNER JOIN FLEET f
ON t.LicencePlate = f.LicencePlate
WHERE t.CheckedOut < par_DateTo AND t.CheckedIn > par_DateFrom
GROUP BY t.LicencePlate
,f.Make
,f.Model
,f.Year;
END
Since your predicates are already verifying that all of the columns referenced in the expression are not null:
checkedIn
par_DateTo
checkedOut
par_DateFrom
(The predicates in the WHERE clause require all of those to be non-NULL), you could simplify the expression a bit, to reference each column once, rather than twice:
DATEDIFF(LEAST(t.checkedIn, par_DateTo),GREATEST(t.checkedOut, par_DateFrom))
And (as Gordon already suggested) just repeat that expression where the result is needed.
When we absolutely, positively have to have reference to an alias from a query, the only real option in MySQL is to use an inline view, though this approach has significant performance consequences for large sets.
SELECT v.LicencePlate
, f.Make
, f.Model
, f.Year
, COUNT(v.LicencePlate) AS TotalTrx
, SUM(v.DaysOut) AS TotalDaysOut
, SUM(v.DaysOut)*v.Price AS TotalIncome
FROM ( SELECT t.LicencePlate
, t.Price
, DATEDIFF(
LEAST(t.checkedIn, par_DateTo),
GREATEST(t.checkedOut, par_DateFrom)
) AS DaysOut
FROM TRANSACTIONS t
WHERE t.CheckedOut < par_DateTo
AND t.CheckedIn > par_DateFrom
) v
JOIN FLEET f
ON f.LicencePlate = v.LicencePlate
GROUP
BY v.LicencePlate
, f.Make
, f.Model
, f.Year
That's less performant, and less elegant, than just simplifying and repeating the expression.
You can't do that. You cannot reference a column alias at the same level of the select as where it is defined. I'm not sure what the exact error is but the (select TotalDaysOut) doesn't make sense.
So, repeat the expression with the additional multiplication:
SUM(DATEDIFF(IF(checkedIn >par_DateTo, par_DateTo, checkedIn) ,IF(checkedOut <par_DateFrom, par_DateFrom, checkedOut))) AS TotalDaysOut,
SUM(t.Price * DATEDIFF(IF(checkedIn >par_DateTo, par_DateTo, checkedIn) ,IF(checkedOut <par_DateFrom, par_DateFrom, checkedOut))) AS TotalIncome
I have a little query, it goes like this:
It's slightly more complex than it looks, the only issue is using the output of one subquery as the parameter for an IN clause to generate another. It works to some degree - but it only provides the results from the first id in the "IN" clause. Oddly, if I manually insert the record ids "00003,00004,00005" it does give the proper results.
What I am seeking to do is get second level many to many relationship - basically tour_stops have items, which in turn have images. I am trying to get all the images from all the items to be in a JSON string as 'item_images'. As stated, it runs quickly, but only returns the images from the first related item.
SELECT DISTINCT
tour_stops.record_id,
(SELECT
GROUP_CONCAT( item.record_id ) AS in_item_ids
FROM tour_stop_item
LEFT OUTER JOIN item
ON item.record_id = tour_stop_item.item_id
WHERE tour_stop_item.tour_stops_id = tour_stops.record_id
GROUP BY tour_stops.record_id
) AS rel_items,
(SELECT
CONCAT('[ ',
GROUP_CONCAT(
CONCAT('{ \"record_id\" : \"',record_id,'\",
\"photo_credit\" : \"',photo_credit,'\" }')
)
,' ]')
FROM images
WHERE
images.attached_to IN(rel_items) AND
images.attached_table = 'item'
ORDER BY img_order ASC) AS item_images
FROM tour_stops
WHERE
tour_stops.attached_to_tour = $record_id
ORDER BY tour_stops.stop_order ASC
Both of these below answers I tried, but it did not help. The second example (placing the entire first subquery inside he "IN" statement) not only produced the same results I am already getting, but also increased query time exponentially.
EDIT: I replaced my IN statement with
IN(SELECT item_id FROM tour_stop_item WHERE tour_stops_id = tour_stops.record_id)
and it works, but it brutally slow now. Assuming I have everything indexed correctly, is this the best way to do it?
using group_concat in PHPMYADMIN will show the result as [BLOB - 3B]
GROUP_CONCAT in IN Subquery
Any insights are appreciated. Thanks
I am surprised that you can use rel_items in the subquery.
You might try:
concat(',', images.attached_to, ',') like concat('%,', rel_items, ',%') and
This may or may not be faster. The original version was fast presumably because there are no matches.
Or, you can try to change your in clause. Sometimes, these are poorly optimized:
exists (select 1
from tour_stop_item
where tour_stops_id = tour_stops.record_id and images.attached_to = item_id
)
And then be sure you have an index on tour_stop_item(tour_stops_id, item_id).