The GROUP BY statement in my SQL query failed to get data - sql

I'm writing an SQL query using GROUP BY, but on executing the GROUP BY statement, I get an error.
$data = DB::table('artisantypes')
->SELECT(DB::Raw("artisantypes.max_seat as max_size,3956 * 2 * ASIN(SQRT(POWER(SIN(('$current_lat' - artisans.driver_lat) * pi()/180 / 2), 2)+ COS('$current_lat' * pi()/180 ) * COS(artisans.driver_lat * pi()/180) * POWER(SIN(('$current_lng' - artisans.driver_lng) * pi()/180 / 2), 2) )) as distance,artisans.driver_lat,artisans.driver_lng" ))
->leftjoin('artisans','artisantypes.id', '=','artisans.car_id' )
->WHERE([['artisantypes.id' ,'=', $car_type],['artisans.artstatus', '=' , 0]])
->groupby('artisans.id')
->HAVING('distance' ,'<', 25)
->orderby ('distance', 'ASC' )
->LIMIT( 0,1)
->get();
Error
SQLSTATE[42000]: Syntax error or access violation: 1055
'sloyd.artisantypes.max_seat' isn't in GROUP BY

Related

Running a raw query with parameter bindings has no result

My sql statement returns null after using DB Raw.No data is produced after passing the request to postman
$current_lat = $request->latitude;
$current_lng = $request->longitude;
$car_type = $request->car_type;
$raw = DB::Raw("(3956 * 2 * ASIN(SQRT(POWER(SIN(('.$current_lat.' - artisans.driver_lat)
* pi()/180 / 2), 2)+ COS('.$current_lat.' * pi()/180 )
* COS(artisans.driver_lat * pi()/180)
* POWER(SIN(('.$current_lng.' - artisans.driver_lng)
* pi()/180 / 2), 2) )))");
return json_encode($raw);
The results is: {}
When I try querying directly in the database, it returns an output as:
4
0.03677850072504271
6.6701784633102145
-1.562010571360574
I think it should look like this
DB::table('artisans')
->select(DB::Raw("your raw"))
->get();
Try DB::select like this:
$results = DB::select('select (3956 * 2 * ASIN(SQRT(POWER(SIN((? - artisans.driver_lat)
* pi()/180 / 2), 2)+ COS(? * pi()/180 )
* COS(artisans.driver_lat * pi()/180)
* POWER(SIN((? - artisans.driver_lng)
* pi()/180 / 2), 2) ))) from artisans', [$current_lat, $current_lat, $current_lng]);
This also provides protection against SQL injection. Check Laravel docs for more info.

SQLite Query Execution on meeting a Condition

I am trying to come up with an SQLite query which would retrieve all the row values between two given values (A and B) in the query,upon meeting a condition.
if (value B given is greater than the maximum value of B in the table):
- retrieve all values between A and B
Sample Table: inventory
Prod_name | model | location |
tesla | "5.6.1" | CA
toyota | "4.7.1" | WA
kia | "6.8.1" | MD
tesla | "2.6.2" | CA
chev | "7.8.4" | AZ
Input given : model between ("5.0.0" to "8.2.0")
Output : (telsa,5.6.1,CA),(kia,6.8.1,MD) , (chev,7.8.4,AZ)
Input given : model between ("5.0.0" to "6.9.0")
Output: Query should not run as "7.8.4" > "6.9.0"
i.e ( the max value in the table is greater than the upper limit of input query.
Also to note is the model name is TEXT format. I need help to retrieving
I have tried "CASE" statements of sqlite but was not able to retrieve
multiple columns in the subquery.
select
case
when (select 1000000 * replace(model, '.', 'x') +
1000 * replace(substr(model, instr(model, '.') + 1), '.', 'x') +
replace(model, '.', '000') % 1000 as md from inventory ORDER BY md
DESC LIMIT 1) > (select 1000000 * replace('5.0.0', '.', 'x') +
1000 * replace(substr('5.0.0', instr('5.0.0', '.') + 1), '.', 'x') +
replace('5.0.0', '.', '000') % 1000)
THEN (select model from inventory where
1000000 * replace(model, '.', 'x') +
1000 * replace(substr(model, instr(model, '.') + 1), '.', 'x') +
replace(model, '.', '000') % 1000
between
1000000 * replace('5.0.0' '.', 'x') +
1000 * replace(substr(''5.0.0'', instr('5.0.0', '.') + 1), '.',
'x') +
replace('5.0.0', '.', '000') % 1000
and
1000000 * replace('8.5.0', '.', 'x') +
1000 * replace(substr('8.5.0', instr('8.5.0', '.') + 1), '.', 'x') +
replace('8.5.0', '.', '000') % 1000 )
END from inventory
I believe that the following will do what you want :-
/* Query using model in n.n.n format */
SELECT * FROM inventory
WHERE
((1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000)
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
/* MAX COndition */
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(
SELECT MAX(((1000000 * substr(model,1,instr(model,'.')-1))
+ (1000 * replace(substr(model,instr(model,'.') + 1),'.','x'))
+ replace(model,'.','000') % 1000))
FROM inventory
)
ORDER BY
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
;
I am curious to know how this could be used in the current solution.
Or if you have any other approach ?
I would suggest that you are grossly over-complicating matters by using a model that is formatted as n.n.n.
If you were to convert that model to an integer value matters could be greatly simplified.
If you really want to keep the model as n.n.n then perhaps ALTER the table to add a column that stores the model as an integer. e.g. you could, as a one of, use :-
ALTER TABLE inventory ADD COLUMN model_value INTEGER DEFAULT -1;
This adds the column model_value
The ALTER could be followed by a mass UPDATE to then set the values for existing rows e.g. :-
UPDATE inventory SET model_value =
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000;
To circumvent needing to change the insert and pre-calculate the model_value, you could add an AFTER INSERT TRIGGER e.g. :-
CREATE TRIGGER IF NOT EXISTS inventory_generate_modelvalue AFTER INSERT ON inventory
BEGIN
UPDATE inventory
SET model_value = (1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
WHERE model_value < 0 OR model_value IS NULL
;
END;
Note that if you currently use INSERT without specifying the columns, then the insert would have to be adjusted to specify the columns to be used for the insert, OR you could hard code -1 or NULL for the new column.
The query would then be simpler as :-
/* Query using model_value) */
SELECT * FROM inventory
WHERE model_value
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(SELECT MAX(model_value) FROM inventory)
ORDER BY model_value
;
If you wanted convert the model value to n.n.n format you could use base this upon :-
SELECT prod_name,
CAST (model_value / 1000000 AS TEXT)
||'.'
|| CAST((model_value % 1000000) / 1000 AS TEXT)
||'.'
||CAST(model_value % 1000 AS TEXT)
AS model,
location
FROM inventory;
Of course if you had a function within your program or used integer values rather than n.n.n then matters would be even simpler.
Testing
The following code was used for testing the above :-
DROP TABLE IF EXISTS inventory;
DROP TRIGGER IF EXISTS inventory_generate_modelvalue;
CREATE TABLE IF NOT EXISTS inventory (prod_name TEXT ,model TEXT,location TEXT);
INSERT INTO inventory VALUES ('tesla','5.6.1','CA'),('toyota','4.7.1','WA'),('kia','6.8.1','MD'),('tesla','2.6.2','CA'),('chev','7.8.4','AZ') ;
/* Add new column for model as an integer value */
ALTER TABLE inventory ADD COLUMN model_value INTEGER DEFAULT -1;
/* Update existing data for new column */
UPDATE inventory SET model_value =
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000;
CREATE TRIGGER IF NOT EXISTS inventory_generate_modelvalue AFTER INSERT ON inventory
BEGIN
UPDATE inventory
SET model_value = (1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
WHERE model_value < 0 OR model_value IS NULL
;
END;
-- INSERT INTO inventory VALUES('my new model','5.0.1','AA',null),('another','0.999.999','ZZ',-1);
SELECT * FROM inventory;
/* Query using model in n.n.n format */
SELECT * FROM inventory
WHERE
((1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000)
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
/* MAX COndition */
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(
SELECT MAX(((1000000 * substr(model,1,instr(model,'.')-1))
+ (1000 * replace(substr(model,instr(model,'.') + 1),'.','x'))
+ replace(model,'.','000') % 1000))
FROM inventory
)
ORDER BY
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
;
/* Query using model_value) */
SELECT * FROM inventory
WHERE model_value
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(SELECT MAX(model_value) FROM inventory)
ORDER BY model_value
;
SELECT prod_name,
CAST (model_value / 1000000 AS TEXT)
||'.'
|| CAST((model_value % 1000000) / 1000 AS TEXT)
||'.'
||CAST(model_value % 1000 AS TEXT)
AS model,
location
FROM inventory;

SQL -Place 2 decimal places in a runtime select -SQL

I have this select query :
SELECT Nombre, Tipo, Descripcion,Abierto,Cerrado, Latitud, Longitud,
SQRT( POW( 69.1 * ( Latitud - 19.55385 ) , 2 )
+ POW( 69.1 * ( - 99.21716 - Longitud )
* COS( Latitud / 57.3 ) , 2 ) ) AS distance
FROM Clientes
It works ok, but it sometimes returns a really long number (many decimal places) and I would like it to return the value with a decimal point with just two places.
I allready tried
CONVERT(DECIMAL(10,2),distance)
but I think my code is badly written.
It would be much appreciated if someone could give me an example or something!
Sorry for my english, I hope it's understandable. And thanks in advance!!
Use the function Round() to mathematical round and Cast to adjust the precision
Ex:
select Cast(ROUND(- 99.2171600000009669 ,2) as decimal(10,2))
Result
-99.22
In your query:
SELECT Nombre, Tipo, Descripcion,Abierto,Cerrado, Latitud, Longitud,
Cast(ROUND(SQRT( POW( 69.1 * ( Latitud - 19.55385 ) , 2 )
+ POW( 69.1 * ( - 99.21716 - Longitud )
* COS( Latitud / 57.3 ) , 2 ) ) ,2) as decimal(10,2)) AS distance
FROM Clientes
Order By Distance Desc

Convert Recursive CTE to Recursive Subquery

How would I convert the following CTE into a recursive subquery? It's an implementation of Newtons Method.
Reasons:
1) I have no permissions to create functions or stored procs in the DB
2) I must do everything in TSQL
3) Not using Oracle
TESTDATA Table
PMT t V
6918.26 6 410000
3636.51 14 460000
3077.98 22 630000
1645.14 18 340000
8591.67 13 850000
Desired Output
PMT t V Newton
6918.26 6 410000 0.066340421
3636.51 14 460000 0.042449138
3077.98 22 630000 0.024132674
1645.14 18 340000 0.004921588
8591.67 13 850000 0.075982984
_
DECLARE #PMT AS FLOAT
DECLARE #t AS FLOAT
DECLARE #V AS FLOAT
--These will be only for 1 example.
SET #PMT = 6918.26740930922
SET #t = 6
SET #V = 410000
;With Newton (n, i,Fi,dFi) AS (
--base
SELECT
1,
CAST(0.1 AS FLOAT)
,#PMT * (1 - POWER((1 + CAST(0.1 AS FLOAT) / 12), (-#t * 12))) - #V * CAST(0.1 AS FLOAT) / 12
,#PMT * #t * 12 * POWER((1 + CAST(0.1 AS FLOAT) / 12), (-#t * 12 - 1)) - #V
UNION ALL
--recursion
SELECT
n + 1
,i - Fi/dFi
,#PMT * (1 - POWER((1 + i / 12), (-#t * 12))) - #V * i / 12
,#PMT * #t * 12 * POWER((1 + i / 12), (-#t * 12 - 1)) - #V
FROM Newton WHERE n < 500)
--to get the desired value for params above
SELECT [x].i
FROM (
SELECT n, i, Fi, dFi
FROM Newton
WHERE n = 500
) [x]
OPTION (MAXRECURSION 500)
_
I want Newton to evaluate on Every record of TestData as a stand alone column.
Any thoughts?

Seeking SQL syntax with errors using HAVING with assigned variable

I am looking for the SQL syntax to use HAVING in the following statement:
DECLARE #ORIG_LAT AS FLOAT = 40.4882011413574;
DECLARE #ORIG_LONG AS FLOAT = -80.1939010620117;
DECLARE #DISTANCE AS INT;
SELECT LATITUDE_DEG, LONGITUDE_DEG,SQRT(
POWER(69.1 * (LATITUDE_DEG - #ORIG_LAT), 2) +
POWER(69.1 * (#ORIG_LONG - LONGITUDE_DEG) * COS(LATITUDE_DEG / 57.3), 2)) AS DISTANCE
FROM NAVAIDS
HAVING DISTANCE < 80 --error
ORDER BY DISTANCE ASC;
Error:
Msg 207, Level 16, State 1, Line 9
Invalid column name 'distance'.
It's ok with the ORDER BY but I don't understand why it doesn't like the HAVING. Any help with direction? It is SQL Server 2008 R2
As you have noticed, you can't use an aliased column directly. The easiest solution would be to wrap your statement in a subselect and apply your clause on that.
SELECT *
FROM (
SELECT LATITUDE_DEG
, LONGITUDE_DEG
, SQRT(
POWER(69.1 * (LATITUDE_DEG - #ORIG_LAT), 2) +
POWER(69.1 * (#ORIG_LONG - LONGITUDE_DEG) * COS(LATITUDE_DEG / 57.3), 2)) AS DISTANCE
FROM NAVAIDS
) q
WHERE DISTANCE < 80
ORDER BY
DISTANCE ASC;
select *
from (
SELECT LATITUDE_DEG, LONGITUDE_DEG, SQRT(
POWER(69.1 * (LATITUDE_DEG - #ORIG_LAT), 2)
POWER(69.1 * (#ORIG_LONG - LONGITUDE_DEG) * COS(LATITUDE_DEG / 57.3), 2)
) AS DISTANCE
FROM NAVAIDS
) a
WHERE DISTANCE < 80
ORDER BY DISTANCE