Select query as where condition in Exposed - kotlin-exposed

How to use DSL method to generate a SELECT query in WHERE?
Example:
SELECT *
FROM table
WHERE id IN (
SELECT MAX(id)
FROM table
GROUP BY name
);

Update:
Now Exposed have added InSubQueryOp.
Table.run {
select { id inSubQuery slice(id.max()).selectAll().groupBy(column) }
}
After searching I found this issue on GitHub. wrapAsExpression can be use to compose subquery.
Copy EqOp and transform it to InOp
class InOp(expr1: Expression<*>, expr2: Expression<*>) : ComparisonOp(expr1, expr2, "IN")
Copy eq then transform it to inExpr extension function
infix fun<T, S1: T?, S2: T?> Expression<in S1>.inExpr(other: Expression<in S2>) :
Op<Boolean> = InOp(this, other)
Use them
Table.run {
select { id inExpr wrapAsExpression(slice(id.max()).selectAll().groupBy(column)) }
}
Example output:
SELECT `user`.id, `user`.name, FROM `user` WHERE `user`.id IN (SELECT MAX(`user`.id) FROM `user` GROUP BY `user`.name)

Related

String '(LISTAGG result)' is too long and would be truncated - How to fix this?

SELECT DISTINCT B.ID, LISTAGG(D.PROCESS_ID,',')
FROM table1 A
JOIN table2 B
ON A.ST_ID = B.ST_ID
JOIN table2 C
ON A.ST_ID = C.ST_ID
JOIN table4 D
ON A.ST_ID = C.ST_ID
WHERE B.DATE = '2022-02-02'
AND FL_CD NOT IN ('1','2','3','4','5')
GROUP BY 1
When I run the above code, I'm getting this error- String '(LISTAGG result)' is too long and would be truncated. This is because of PROCESS_ID column as it is having huge values. Kindly provide a solution to fix this.
As many answers are calling, there's probably an exploding join that's creating way more data than expected.
In any case, I created an UDTF in JavaScript that can receive a table and extract a limited number of sample elements for each label — which is basically what the question is asking for:
create or replace function limited_array_agg(arr_limit float, g string, s string)
returns table (G string, S array)
language javascript
as $$
{
processRow: function f(row, rowWriter, context){
if(this.counter < row.ARR_LIMIT){
this.arr.push(row.S)
this.group = row.G
this.counter++;
};
}
, initialize: function(argumentInfo, context) {
this.counter = 0;
this.arr = [];
}, finalize: function(rowWriter, context){
rowWriter.writeRow({G:this.group, S: this.arr})
}
}
$$;
You can use it like this, where your query could be a CTE:
select limited_agg.g, limited_agg.s
from snowflake_sample_data.tpch_sf100.part
, table(limited_array_agg(
3::float
, p_mfgr
, p_name) over(partition by p_mfgr)) limited_agg
;
In the meantime: I wish Snowflake had a native array_agg() that limits the number of elements.

T-SQL Json_modify to append a property to each object

I have a stored procedure that accepts a JSON string as input parameter. The input JSON string is like this:
[
{
"name":"Jhon",
"surname":"Smith",
"skills":["C#","VB.NET"]
},
{
"name":"Robert",
"surname":"Jhonson",
"skills":["T-SQL","Pascal"]
}
]
How can I add a unique GUID property to each principal object automatically?
Looking at your example data you already discovered this page of the documentation that tells you how to insert values with the json_modify() function. The examples on that page are written for a single "principal object".
If I interpret this correctly, then your sample has 2 principle objects. Using another page of the documentation shows how you can split that sample in rows with the openjson() function. You can then apply the json_modify() from the first documentation page on each row.
declare #var nvarchar(max) =
'[
{
"name":"Jhon",
"surname":"Smith",
"skills":["C#","VB.NET"]
},
{
"name":"Robert",
"surname":"Jhonson",
"skills":["T-SQL","Pascal"]
}
]';
select row_number() over(order by (select null)) as ObjNumber,
json_modify(j.value, '$.guid', convert(nvarchar(100), newid())) as ObjValue
from openjson(#var, '$') j
The result looks like this:
ObjNumber ObjValue
----------- ----------------------------------------------------
1 {
"name":"Jhon",
"surname":"Smith",
"skills":["C#","VB.NET"]
,"guid":"154C5581-588C-41AA-B292-BB6459F8F4DC"}
2 {
"name":"Robert",
"surname":"Jhonson",
"skills":["T-SQL","Pascal"]
,"guid":"46ACFDD6-58DE-4DB0-8D7A-9B1CCABFF8D8"}
Fiddle
To add the rows back together, just add for json path. This does however require a field alias (here MyObjects) that ends up in the output.
select json_modify(j.value, '$.guid', convert(nvarchar(100), newid())) as MyObjects
from openjson(#var, '$') j
for json path;
Output:
[{"MyObjects":{
"name":"Jhon",
"surname":"Smith",
"skills":["C#","VB.NET"]
,"guid":"FCED4D30-B2B0-460B-97FA-EDA820039572"}},{"MyObjects":{
"name":"Robert",
"surname":"Jhonson",
"skills":["T-SQL","Pascal"]
,"guid":"9FF02A70-0455-4E5C-8C11-27BB2688929D"}}]
Fiddle
To update the variable use the following code. Bonus: replace() removes the previously added field alias.
set #var = replace(
( select json_modify(j.value, '$.guid', convert(nvarchar(100), newid())) as MyObjects
from openjson(#var, '$') j
for json path ),
'"MyObjects":', '');
Final output for select #var:
[{{
"name":"Jhon",
"surname":"Smith",
"skills":["C#","VB.NET"]
,"guid":"66CB37D3-FAEF-4186-94D8-8AC0CF6EB1AC"}},{{
"name":"Robert",
"surname":"Jhonson",
"skills":["T-SQL","Pascal"]
,"guid":"564D6904-D981-40AC-BA9C-8B06015ACE50"}}]
Fiddle

SQL Server: How to remove a key from a Json object

I have a query like (simplified):
SELECT
JSON_QUERY(r.SerializedData, '$.Values') AS [Values]
FROM
<TABLE> r
WHERE ...
The result is like this:
{ "2019":120, "20191":120, "201902":121, "201903":134, "201904":513 }
How can I remove the entries with a key length less then 6.
Result:
{ "201902":121, "201903":134, "201904":513 }
One possible solution is to parse the JSON and generate it again using string manipulations for keys with desired length:
Table:
CREATE TABLE Data (SerializedData nvarchar(max))
INSERT INTO Data (SerializedData)
VALUES (N'{"Values": { "2019":120, "20191":120, "201902":121, "201903":134, "201904":513 }}')
Statement (for SQL Server 2017+):
UPDATE Data
SET SerializedData = JSON_MODIFY(
SerializedData,
'$.Values',
JSON_QUERY(
(
SELECT CONCAT('{', STRING_AGG(CONCAT('"', [key] ,'":', [value]), ','), '}')
FROM OPENJSON(SerializedData, '$.Values') j
WHERE LEN([key]) >= 6
)
)
)
SELECT JSON_QUERY(d.SerializedData, '$.Values') AS [Values]
FROM Data d
Result:
Values
{"201902":121,"201903":134,"201904":513}
Notes:
It's important to note, that JSON_MODIFY() in lax mode deletes the specified key if the new value is NULL and the path points to a JSON object. But, in this specific case (JSON object with variable key names), I prefer the above solution.

N1QL : Find latest status from an array

I have a document of type 'User' as-
{
"id":"User-1",
"Name": "Kevin",
"Gender":"M",
"Statuses":[
{
"Status":"ONLINE",
"StatusChangedDate":"2017-11-01T17:12:00Z"
},
{
"Status":"OFFLINE",
"StatusChangedDate":"2017-11-02T13:24:00Z"
},
{
"Status":"ONLINE",
"StatusChangedDate":"2017-11-02T14:35:00Z"
},
{
"Status":"OFFLINE",
"StatusChangedDate":"2017-11-02T15:47:00Z"
}.....
],
"type":"User"
}
I need user's information along with his latest status details based on a particular date (or date range).
I am able to achieve this using subquery and Unnest clause.
Select U.Name, U.Gender, S.Status, S.StatusChangedDate
From (Select U1.id, max(U1.StatusChangedDate) as StatusChangedDate
From UserInformation U1
Unnest Statuses S1
Where U1.type = 'User'
And U1.StatusChangedDate between '2017-11-02T08:00:00Z' And '2017-11-02T11:00:00Z'
And U1.Status = 'ONLINE'
Group by U1.id
) A
Join UserInformation U On Keys A.id
Unnest U.Statuses S
Where U.StatusChangedDate = A.StatusChangedDate;
But is there any other way of achieving this (like by using collection operators and array functions)??
If yes, please provide me a query or guide me through it.
Thanks.
MAX, MIN argument allows array. 0th element of array can be field needs aggregate and 1st element is what you want to carry.
Using this techinuqe you can project non aggregtae field for MIN/MAX like below.
SELECT U.Name, U.Gender, S.Status, S.StatusChangedDate
FROM UserInformation U1
UNNEST Statuses S1
WHERE U1.type = 'User'
AND S1.StatusChangedDate BETWEEN '2017-11-02T08:00:00Z' AND '2017-11-02T11:00:00Z'
AND S1.Status = 'ONLINE'
GROUP BY U1.id
LETTING S = MAX([S1.StatusChangedDate,S1])[1];
In 4.6.3+ you can also try this without UNNEST Using subquery expressions https://developer.couchbase.com/documentation/server/current/n1ql/n1ql-language-reference/subqueries.html . Array indexing query will be faster.
CREATE INDEX ix1 ON UserInformation(ARRAY v FOR v IN Statuses WHEN v.Status = 'ONLINE' END) WHERE type = "User";
SELECT U.Name, U.Gender, S.Status, S.StatusChangedDate
FROM UserInformation U1
LET S = (SELECT RAW MAX([S1.StatusChangedDate,S1])[1]
FROM U1.Statuses AS S1
WHERE S1.StatusChangedDate BETWEEN '2017-11-02T08:00:00Z' AND '2017-11-02T11:00:00Z' AND S1.Status = 'ONLINE')[0]
WHERE U1.type = 'User'
AND ANY v IN U1.Statuses SATISFIES
v.StatusChangedDate BETWEEN '2017-11-02T08:00:00Z' AND '2017-11-02T11:00:00Z' AND v.Status = 'ONLINE' END;

how to count total left and total right child of a user in downline in a MLM binary Tree in SQL CTE

I am facing some of problem while getting the following result from a parent child relationship please check the follwing table structure.
The above is the table structure and the tree structure is like below image.
in case of my scenario here is an MLM tree in which every person have down line members on left side and right side.so i need to calculate this for the current login user in their down line
So i need the right side summary recursively thanks in advance
ALTER Function [dbo].[F_SearchUsersTreeByParent](#id as int)
Returns table as
Return
WITH CTE_Table (id, FullName,UserName, RefferdByID,Levels,LevelPrice, IsPurchasedProduct)
AS
(
SELECT id, FullName,UserName,-1 as RefferdByID,Levels,LevelPrice,IsPurchasedProduct
FROM Registration WHERE id = #id and Registration.IsPurchasedProduct=1
UNION ALL
SELECT Registration.id, Registration.FullName,Registration.UserName, Registration.RefferdByID,Registration.Levels,Registration.LevelPrice, Registration.IsPurchasedProduct FROM Registration
JOIN CTE_Table ON Registration.RefferdByID = CTE_Table.id
where Registration.IsPurchasedProduct=1
)
SELECT id, FullName,UserName, RefferdByID,Levels,LevelPrice, IsPurchasedProduct,
(Select count(*)-1 from dbo.F_CountRefered(id) where id<>abc.id) as RefCount
FROM CTE_Table as abc
$memid="95000"; // your id
function getTotalLeg($memid,$leg){
global $conn;
$sql="select child_class from tree_class where parent_id='".$memid."' and position='".$leg."'";
$res=mysqli_query($conn,$sql);
$row=mysqli_fetch_array($res);
global $total;
$total=$total+mysqli_num_rows($res);
if($row['child_class']!=''){
getTotalLeg ($row['child_class'],'L');
getTotalLeg ($row['child_class'],'R');
}
return $total;
}
$total=0;
$left=getTotalLeg($memid,"L");
echo $total."</br>";
$total=0;
$right=getTotalLeg($memid,"R");
echo $total;

Resources