Sequelize complex aggregate attribute in where and order - sql

Hello I'm trying to use Sequelize to perform location based queries, and I'm having a nightmare!
I'm trying to generate the SQL:
SELECT *, (3959 * acos(cos(radians([user-latitude])) * cos(radians(latitude)) * cos(radians(longitude) - radians([user-longitude])) + sin(radians([user-latitude])) * sin(radians(latitude)))) AS distance FROM myModel HAVING distance <= 25 ORDER BY distance ASC LIMIT 0 , 10;
where [user-latitude] and [user-longitude] are variables. So far I've got this:
myModel.findAll({
attributes: [
'*',
[`(3959 * acos(cos(radians(${user-latitude})) * cos(radians(latitude)) * cos(radians(longitude) - radians(${user-longitude})) + sin(radians(${user-latitude})) * sin(radians(latitude))))`, 'distance'],
],
where: {
distance: {
$lte: 25,
},
},
order: [
['distance', 'ASC'],
],
limit: 10,
offset: 0,
});
which generates:
SELECT *, (3959 * acos(cos(radians([user-latitude])) * cos(radians(latitude)) * cos(radians(longitude) - radians([user-longitude])) + sin(radians([user-latitude)) * sin(radians(latitude)))) AS `distance` FROM `myModels` AS `myModel` WHERE `myModel`.`distance` <= 15 ORDER BY `myModel`.`distance` ASC LIMIT 0, 10;
which doesn't work because `myModel`.`distance` is not a field. Is there a way to make this work without using raw queries?

Unfortunately you cannot use alias field in the WHERE or HAVING statement, only in the ORDER BY. You must repeat your statement in the WHERE clause instead using alias (just as it is explained in SQL Use alias in Where statement).
What is more, the error you obtained happens because when you used field distance in the where and order attributes, Sequelize automatically treated it as a field of myModel instead your alias, so you need to write it literally so it won't be treated as a column of table you select.
myModel.findAll({
attributes: {
include: [[`(3959 * acos(cos(radians(${user-latitude})) * cos(radians(latitude)) * cos(radians(longitude) - radians(${user-longitude})) + sin(radians(${user-latitude})) * sin(radians(latitude))))`, 'distance']]
},
where: sequelize.where(
sequelize.literal(`(3959 * acos(cos(radians(${user-latitude})) * cos(radians(latitude)) * cos(radians(longitude) - radians(${user-longitude})) + sin(radians(${user-latitude})) * sin(radians(latitude))))`),
'<=',
25
),
order: 'distance ASC',
limit: 10,
offset: 0
});
sequelize in this case is your instance of Sequelize.

Related

Query key values in a json column

I have a table "jobs" with one of the columns called "check_list" ( varchar(max) that has JSON values, an example value would be
{
"items":[
{
"name":"machine 1",
"state":"",
"comment":"",
"isReleaseToProductionCheck":true,
"mnachine_id":10
},
{
"name":"machine 2",
"state":"",
"comment":"",
"isReleaseToProductionCheck":true,
"machine_id":12
}
]
}
Now how would I write a SQL query to only return the rows where the column "check_list" has items[machine_id] = 12
In the end after some trial and error this was the solution that worked for me. I had to add the ISJSON check because some of the older data was invalid
WITH jobs (id, workorder, selectedMachine) AS(
SELECT
[id],
[workorder],
(
select
*
from
openjson(check_list, '$.items') with (machine_id int '$.machine_id')
where
machine_id = 12
) as selectedMachine
FROM
engineering_job_schedule
WHERE
ISJSON(check_list) > 0
)
Select
*
from
jobs
where
selectedMachine = 12

Snowflake get_path() or flatten() array query - to find latest key:value

I have a column 'amp' in a table 'EXAMPLE'. Column 'amp' is an array which looks like this:
[{
"list": [{
"element": {
"x_id": "12356789XXX",
"y_id": "12356789XXX38998",
}
},
{
"element": {
"x_id": "5677888356789XXX",
"y_id": "1XXX387688",
}
}]
}]
How should I query using get_path() or flatten() to extract the latest x_id and y_id value (or other alternative)
In this example it is only 2 elements, but there could 1 to 6000 elements containing x_id and y_id.
Help much appreciated!
Someone may have a more elegant way than this, but you can use a CTE. In the first table expression, grab the max of the array. In the second part, grab the values you need.
set json = '[{"list": [{"element": {"x_id": "12356789XXX","y_id": "12356789XXX38998"}},{"element": {"x_id": "5677888356789XXX","y_id": "1XXX387688",}}]}]';
create temp table foo(v variant);
insert into foo select parse_json($json);
with
MAX_INDEX(M) as
(
select max("INDEX") MAX_INDEX
from foo, lateral flatten(v, recursive => true)
),
VALS(V, P, K) as
(
select "VALUE", "PATH", "KEY"
from foo, lateral flatten(v, recursive => true)
)
select k as "KEY", V::string as VALUE from vals, max_index
where VALS.P = '[0].list[' || max_index.m || '].element.x_id' or
VALS.P = '[0].list[' || max_index.m || '].element.y_id'
;
Assuming that the outer array ALWAYS contains a single dictionary element, you could use this:
SELECT amp[0]:"list"[ARRAY_SIZE(amp[0]:"list")-1]:"element":"x_id"::VARCHAR AS x_id
,amp[0]:"list"[ARRAY_SIZE(amp[0]:"list")-1]:"element":"y_id"::VARCHAR AS y_id
FROM T
;
Or if you prefer a bit more modularity/readability, you could use this:
WITH CTE1 AS (
SELECT amp[0]:"list" AS _ARRAY
FROM T
)
,CTE2 AS (
SELECT _ARRAY[ARRAY_SIZE(_ARRAY)-1]:"element" AS _DICT
FROM CTE1
)
SELECT _DICT:"x_id"::VARCHAR AS x_id
,_DICT:"y_id"::VARCHAR AS y_id
FROM CTE2
;
Note: I have not used FLATTEN here because I did not see a good reason to use it.

MDX - multiple filters on different dimension with OR condition

I have a problem with MDX querying.
I have one measure WEIGHT and two dimensions DESTINATION and SOURCE with the same attributes: NAME and TYPE.
I want to return:
SUM of WEIGHT
where
DESTINATION.TYPE="A"
**OR**
SOURCE.TYPE="B"
**AND**
(DESTINATION.TYPE **<>** SOURCE.TYPE)
If try this:
SELECT NON EMPTY {
[Measures].[Weight]
}
ON COLUMNS,
NON EMPTY {
([Source].[Name].[Name].ALLMEMBERS * [Destination].[Name].[Name].ALLMEMBERS )
}
ON ROWS
FROM
( SELECT ( { [Source].[Type].&[A] } ) ON COLUMNS FROM ( SELECT ( { [Destination].[Type].&[B] } )
ON COLUMNS FROM [CUBE])) WHERE ( [Destination].[Type].&[B], [Source].[Type].&[A] )
But it doesn't work.
In SQL it look like
Select source.name, destination.name, sum(weight) from cube
where
(source.type = "A" or destination.type = "b")
and
(source.type <> destination.type)
group by source.name, destination.name, source.type, destination.type
Your From section is a bit messy. Try the following:
SELECT
NON EMPTY { [Measures].[Weight] } ON COLUMNS,
NON EMPTY { [Source].[Name].[Name].ALLMEMBERS * [Destination].[Name].[Name].ALLMEMBERS } ON ROWS
FROM [CUBE]
WHERE ( {[Destination].[Type].&[B]} * {[Source].[Type].[All]} + {[Destination].[Type].[All]} * {[Source].[Type].&[A]} )

How do you get the total rows in an MDX query to use for paging?

I am attempting to implement paging to large datasets in MDX (SSAS).
I have the following to retrieve paged data which works fine:
SELECT
{
[Measures].[Mesasure1],
[Measures].[Measure2]
} ON COLUMNS,
SUBSET
(
ORDER
(
{
(
[Item].[Category].ALLMEMBERS
)
}, NULL, BASC
), 10, 50 --10 = start index, 50 = returned roes
)
ON ROWS
FROM ( SELECT ( { [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] } ) ON COLUMNS
FROM [DataMartPerformance]
))
However I cannot for the life of me find anywhere on the internet that helps explain how to get the total rows available. Do I do it in a seperate query? If so how?
Or can I wrap it into this one query somehow?
Similar to how you'd do TSQL paging, you'll need to run another query to count the total elements. You may have to tinker with this depending on how you've done your original query, but I use something like:
WITH
MEMBER [Measures].[ElementCount] AS
{
NONEMPTY
(
{
[Item].[Category].ALLMEMBERS *
{ [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] }
},
{
[Measures].[Mesasure1],
[Measures].[Measure2]
}
)
}.COUNT
SELECT
{
[Measures].[ElementCount]
}
ON COLUMNS
FROM
[DataMartPerformance]
For filtering, you can do dimension filters by using an exists against your dimension attributes:
WITH
MEMBER [Measures].[ElementCount] AS
{
NONEMPTY
(
EXISTS
(
{
[Item].[Category].ALLMEMBERS *
{ [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] }
},
{
[Dimension].[Attribute].[FilterByThisAttribute]
}
),
{
[Measures].[Mesasure1],
[Measures].[Measure2]
}
)
}.COUNT
SELECT
{
[Measures].[ElementCount]
}
ON COLUMNS
FROM
[DataMartPerformance]
I haven't got to writing the measure value filters yet, I need to do that next for my own MDX paging constructor...
Please try this:
WITH
SET MySet As
(
NONEMPTY (
[AU Time Sale Hour].[Hour Key].[Hour Key]
* [Dim Country].[Country Key].[Country Key]
)
)
Member [Measures] .cnt AS MySet.Count
select [Measures] .cnt on Columns
from [Me Stats DW Fact Sales]
where (
{[Dim Visa].[Visa Key].&[2067],[Dim Visa].[Visa Key].&[2068] },
[AU Time Sale Date].[Date].&[20091120]:[AU Time Sale Date].[Date].&[20091125]
)

Linq to LLBLGen query problem

I've got a Stored Procedure and i'm trying to convert it to a Linq to LLBLGen query. The query in Linq to LLBGen works, but when I trace the query which is send to sql server it is far from perfect.
This is the Stored Procedure:
ALTER PROCEDURE [dbo].[spDIGI_GetAllUmbracoProducts]
-- Add the parameters for the stored procedure.
#searchText nvarchar(255),
#startRowIndex int,
#maximumRows int,
#sortExpression nvarchar(255) AS BEGIN
SET #startRowIndex = #startRowIndex + 1
SET #searchText = '%' + #searchText + '%'
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- This is the query which will fetch all the UmbracoProducts.
-- This query also supports paging and sorting.
WITH UmbracoOverview As
(
SELECT ROW_NUMBER() OVER(
ORDER BY
CASE
WHEN #sortExpression = 'productName' THEN umbracoProduct.productName
WHEN #sortExpression = 'productCode' THEN umbracoProduct.productCode
END ASC,
CASE
WHEN #sortExpression = 'productName DESC' THEN umbracoProduct.productName
WHEN #sortExpression = 'productCode DESC' THEN umbracoProduct.productCode
END DESC )
AS row_num, umbracoProduct.umbracoProductId, umbracoProduct.productName, umbracoProduct.productCode
FROM umbracoProduct INNER JOIN
product ON umbracoProduct.umbracoProductId = product.umbracoProductId
WHERE (umbracoProduct.productName LIKE #searchText
OR umbracoProduct.productCode LIKE #searchText
OR product.code LIKE #searchText
OR product.description LIKE #searchText
OR product.descriptionLong LIKE #searchText
OR product.unitCode LIKE #searchText)
)
SELECT UmbracoOverview.UmbracoProductId, UmbracoOverview.productName, UmbracoOverview.productCode
FROM UmbracoOverview
WHERE (row_num >= #startRowIndex
AND row_num < (#startRowIndex + #maximumRows))
-- This query will count all the UmbracoProducts.
-- This query is used for paging inside ASP.NET.
SELECT COUNT (umbracoProduct.umbracoProductId) AS CountNumber
FROM umbracoProduct INNER JOIN
product ON umbracoProduct.umbracoProductId = product.umbracoProductId
WHERE (umbracoProduct.productName LIKE #searchText
OR umbracoProduct.productCode LIKE #searchText
OR product.code LIKE #searchText
OR product.description LIKE #searchText
OR product.descriptionLong LIKE #searchText
OR product.unitCode LIKE #searchText) END
This is my Linq to LLBLGen query:
using System.Linq.Dynamic;
var q = (
from up in MetaData.UmbracoProduct
join p in MetaData.Product on up.UmbracoProductId equals p.UmbracoProductId
where up.ProductCode.Contains(searchText) ||
up.ProductName.Contains(searchText) ||
p.Code.Contains(searchText) ||
p.Description.Contains(searchText) ||
p.DescriptionLong.Contains(searchText) ||
p.UnitCode.Contains(searchText)
select new UmbracoProductOverview
{
UmbracoProductId = up.UmbracoProductId,
ProductName = up.ProductName,
ProductCode = up.ProductCode
}
).OrderBy(sortExpression);
//Save the count in HttpContext.Current.Items. This value will only be saved during 1 single HTTP request.
HttpContext.Current.Items["AllProductsCount"] = q.Count();
//Returns the results paged.
return q.Skip(startRowIndex).Take(maximumRows).ToList<UmbracoProductOverview>();
This is my Initial expression to process:
value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource`1[Eurofysica.DB.EntityClasses.UmbracoProductEntity]).Join(value(SD.LLBLGen.Pro.LinqSupportClasses.DataSource`1[Eurofysica.DB.EntityClasses.ProductEntity]), up => up.UmbracoProductId, p => p.UmbracoProductId, (up, p) => new <>f__AnonymousType0`2(up = up, p = p)).Where(<>h__TransparentIdentifier0 => (((((<>h__TransparentIdentifier0.up.ProductCode.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText) || <>h__TransparentIdentifier0.up.ProductName.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText)) || <>h__TransparentIdentifier0.p.Code.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText)) || <>h__TransparentIdentifier0.p.Description.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText)) || <>h__TransparentIdentifier0.p.DescriptionLong.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText)) || <>h__TransparentIdentifier0.p.UnitCode.Contains(value(Eurofysica.BusinessLogic.BLL.Controllers.UmbracoProductController+<>c__DisplayClass1).searchText))).Select(<>h__TransparentIdentifier0 => new UmbracoProductOverview() {UmbracoProductId = <>h__TransparentIdentifier0.up.UmbracoProductId, ProductName = <>h__TransparentIdentifier0.up.ProductName, ProductCode = <>h__TransparentIdentifier0.up.ProductCode}).OrderBy( => .ProductName).Count()
Now this is how the queries look like that are send to sql server:
Select query:
Query: SELECT [LPA_L2].[umbracoProductId] AS [UmbracoProductId], [LPA_L2].[productName] AS [ProductName], [LPA_L2].[productCode] AS [ProductCode] FROM ( [eurofysica].[dbo].[umbracoProduct] [LPA_L2] INNER JOIN [eurofysica].[dbo].[product] [LPA_L3] ON [LPA_L2].[umbracoProductId] = [LPA_L3].[umbracoProductId]) WHERE ( ( ( ( ( ( ( ( [LPA_L2].[productCode] LIKE #ProductCode1) OR ( [LPA_L2].[productName] LIKE #ProductName2)) OR ( [LPA_L3].[code] LIKE #Code3)) OR ( [LPA_L3].[description] LIKE #Description4)) OR ( [LPA_L3].[descriptionLong] LIKE #DescriptionLong5)) OR ( [LPA_L3].[unitCode] LIKE #UnitCode6))))
Parameter: #ProductCode1 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #ProductName2 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #Code3 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #Description4 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #DescriptionLong5 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #UnitCode6 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Count query:
Query: SELECT TOP 1 COUNT(*) AS [LPAV_] FROM (SELECT [LPA_L2].[umbracoProductId] AS [UmbracoProductId], [LPA_L2].[productName] AS [ProductName], [LPA_L2].[productCode] AS [ProductCode] FROM ( [eurofysica].[dbo].[umbracoProduct] [LPA_L2] INNER JOIN [eurofysica].[dbo].[product] [LPA_L3] ON [LPA_L2].[umbracoProductId] = [LPA_L3].[umbracoProductId]) WHERE ( ( ( ( ( ( ( ( [LPA_L2].[productCode] LIKE #ProductCode1) OR ( [LPA_L2].[productName] LIKE #ProductName2)) OR ( [LPA_L3].[code] LIKE #Code3)) OR ( [LPA_L3].[description] LIKE #Description4)) OR ( [LPA_L3].[descriptionLong] LIKE #DescriptionLong5)) OR ( [LPA_L3].[unitCode] LIKE #UnitCode6))))) [LPA_L1]
Parameter: #ProductCode1 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #ProductName2 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #Code3 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #Description4 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #DescriptionLong5 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
Parameter: #UnitCode6 : String. Length: 2. Precision: 0. Scale: 0. Direction: Input. Value: "%%".
As you can see no sorting or paging is done (like in my Stored Procedure). This is probably done inside the code after all the results are fetched. This costs a lot of performance! Does anybody know how I can convert my Stored Procedure to Linq to LLBLGen the proper way?
Have you tried using TakePage() instead of Skip/Take? The docs say this is preferred and I have run into some weird problems with Skip/Take.
I think the OrderBy clause might be better in the return statement? I doubt that's the root of the problem, though.
So maybe try:
return q.OrderBy(sortExpression).TakePage(pageNumber, pageSize);