Do I need a temporary table? - mysql

I have the following query and I need to add "and distance < 10" to the where clause. Because 'distance' is computed variable it can't be used in where clause. I have tried HAVING instead of where but that breaks the replace part.
I think the answer is to use a temporary table for the distance computation but i can't figure out the syntax as everything I have tried doesn't work.
All help appreciated please. Thanks.
select
Contractor.contractorID,
Contractor.firstName,
Contractor.lastName,
Contractor.emailAddress,
Contractor.nationality,
Contractor.dateOfBirth,
Contractor.address1,
Contractor.address2,
Contractor.city,
Contractor.county,
Contractor.postcode,
Contractor.country,
Contractor.tel,
Contractor.mob,
postcodes.Grid_N Grid_N1,
postcodes.Grid_E Grid_E1,
(select Grid_N from postcodes where pCode='".$postcode."') Grid_N2,
(select Grid_E from postcodes where pCode='".$postcode."') Grid_E2,
( (select sqrt(((Grid_N1-Grid_N2)*(Grid_N1-Grid_N2))+((Grid_E1-Grid_E2)*(Grid_E1-Grid_E2))) ))/1000*0.621371192 as distance
from
Contractor,
postcodes
where
postcodes.Pcode = replace(substring(Contractor.postcode,1,length(Contractor.postcode)-3),'','')
order by
distance asc

In MySQL, you can do this with:
where . . .
having distance < 10
order by distance;
You don't need to put the other conditions in the having clause. Also, your query could benefit from using ANSI standard join syntax (using the on clause, for instance).

SELECT list
, of
, columns
, including
, distance
FROM (
<your existing query>
/* minus ORDER BY clause (needs to be on outermost query */
) As a_subquery
WHERE distance < 10
ORDER
BY some_stuff

Related

SUM inside SUM SQL Invalid use of group function

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.

Select the nearest point for each row in table

I use this to find the nearest point
SELECT
id,
ST_Distance(
POINT(52.760667210533,-7.22646337599035),
geo_point
) as distance
from Points
order by distance limit 1
I have a temp table TempPoints with all my candidate points and I want to normalise them onto OSM nodes, but there's lots, so I need a single query to resolve them all in one call. UNION wont let me use order by, and my DB raw query interface wont let me just fire a series of queries separated by ';'.
The temp table has lat and lon but can just as easily have a POINT. How can I go
select id,NearestTo(TempPoint.geo_point,Points) from TempPoints;
EDIT: I can parenthesise each select in my large union query, which solves my issue.
I would still like to be able to join on nearest row.
This might work for you:
SELECT t.id as tid, p.id as pid, p.geo_point
FROM TempPoint t
JOIN Points p ON p.id = (
SELECT p1.id
FROM Points p1
ORDER BY ST_Distance(p1.geo_point, t.geo_point)
LIMIT 1
)
My solution is to issue a series of queries, one for each row, and bind them together with a UNION. The mysql stack will blow eventually so you need to do them in blocks, but 1000 is OK on a default install.
You have to parenthesize the queries as they include an order by. Some points may fail so I label them all with a literal line_no sequence so you can edit and filter the originals. You also need to restrict the query with a
WHERE Contains(<polygon>,point)
clause, else it will try and sort the whole table, where polygon is a bounding box you have to cook up with GEOMFROMTEXT() and POLYGON(). And of course you need a special spatial index on the column!. Here's some code
var SMALL=0.001
var=query=points
.map(function(point){
var bottom=point.lat+SMALL
var top=point.lat-SMALL
var left=point.lon-SMALL
var right=point.lon+SMALL
var polygon=[
[bottom,left],
[top,left],
[top,right],
[bottom,right],
[bottom,left]
]
polygon="POLYGON(("+polygon.map(function(point){
return point.join(' ')
})
.join(",")+"))"
point.line_no=line_no++
return "(SELECT "+point.line_no+" as line_no,id, ST_Distance(POINT("+
point.lat+","+point.lon+
"),geo_point) as distance"+
" from Points "+
" WHERE Contains(GeomFromText('"+polygon+"'),geo_point) "+
" order by distance limit 1) "
})
.join(" UNION ")+" order by line_no"
return sequelize.query(query)

Converting SQL Server Query to MySQL Query Using Subquery Alias

everyone.. i have a view in SQL Server that need to be ported to MySQL.
SELECT Geb_ID, Geb_Key, Geb_Jahr, Geb_Parzelle, Geb_Standort,
Geb_GebArtID, Geb_BesID, Geb_boolJB, Geb_Info,
(SELECT TOP (1) Geb_BesID FROM TGebaude AS xGeb
WHERE Geb_Key = a.Geb_Key ORDER BY Geb_Jahr DESC) AS Akt_BesID
FROM TGebaude AS a
I've tried to convert this query using LIMIT 1 (because in MySQL there is no TOP 1) but still not succeed because there is subquery using "a" alias for it's own table. is there any way to convert this query?
There are qualifiers missing in your subquery. (And that shouldn't really be a problem, as the inner/local table should have precedence over the main/outer one.) Apart from this I see no issue. Swap TOP for LIMIT and you should be done. Please try with the qualifiers added:
SELECT
Geb_ID, Geb_Key, Geb_Jahr, Geb_Parzelle, Geb_Standort,
Geb_GebArtID, Geb_BesID, Geb_boolJB, Geb_Info,
(
SELECT Geb_BesID
FROM TGebaude AS xGeb
WHERE xGeb.Geb_Key = a.Geb_Key
ORDER BY xGeb.Geb_Jahr DESC
LIMIT 1
) AS Akt_BesID
FROM TGebaude AS a;

MySQL String Position and Substring sort

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.

Php MySql query by distance and time

I have this query that I would like to add a time search to.
Here is my working query:
$query = "SELECT *,(((acos(sin((".$lat."*pi()/180)) * sin((Lat*pi()/180)) +
cos((".$lat."*pi()/180)) * cos((Lat*pi()/180)) * cos(((".$lon."- Lon) *
pi()/180))))*180/pi())*60*1.1515) as distance
FROM items
HAVING distance < ".$distance."
ORDER BY distance
LIMIT ".$min." , ".$max."";
I would like to add something like this
WHERE timestamp > ".$somePastDate."
For hours now I have tried all combinations I can think of with no luck. I bet its simple too and I'll be shaking my head. Thanks in advance.
I suggest you use a nested query for this, as follows
SELECT *, big_cosine_law_distance_formula AS distance
FROM (
SELECT *
FROM items
WHERE items.timestamp > ".$somePastDate."
) AS i
HAVING distance < ".$distance."
The inner query will narrow down your items by time, so you don't have to grind out the big distance formula on them all.
You might also consider using a faster bounding-box-based search to narrow down your items spatially, as described here. http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
You can troubleshoot this kind of thing by starting with the inner query.
SELECT *
FROM items
WHERE items.timestamp > ".$somePastDate."
When you're getting reliable results from that query, add the outer one.