Working with Structs within Arrays for new BigQuery Standard SQL - sql

I'm trying to find rows with duplicate fields in an array of structs within a Google BigQuery table, using the new Standard SQL. The data in the table (simplified) where each row looks a bit like this:
{
"Session": "abc123",
"Information" [
{
"Identifier": "e8d971a4-ef33-4ea1-8627-f1213e4c67dc"
},
{
"Identifier": "1c62813f-7ec4-4968-b18b-d1eb8f4d9d26"
},
{
"Identifier": "e8d971a4-ef33-4ea1-8627-f1213e4c67dc"
}
]
}
My end goal is to display the rows that have Information entities with duplicate Identifier values present. However, most of the queries I attempt get an error message of the following form:
Cannot access field Identifier on a value with type ARRAY<STRUCT<Identifier STRING>>
Is there a way to work with the data inside of a STRUCT within an ARRAY?
Here's my first attempt at a query:
SELECT
Session,
Information
FROM
`events.myevents`
WHERE
COUNT(DISTINCT Information.Identifier) != ARRAY_LENGTH(Information.Identifier)
LIMIT
1000
And another using a subquery:
SELECT
Session,
Information
FROM (
SELECT
Session,
Information,
COUNT(DISTINCT Information.Identifier) AS info_count_distinct,
ARRAY_LENGTH(Information) AS info_count
FROM
`events.myevents`
WHERE
COUNT(DISTINCT Information.Identifier) != ARRAY_LENGTH(Information.Identifier)
LIMIT
1000)
WHERE
info_count != info_count_distinct

Try below
SELECT Session, Identifier, COUNT(1) AS dups
FROM `events.myevents`, UNNEST(Information)
GROUP BY Session, Identifier
HAVING dups > 1
ORDER BY Session
Should give you what you expect plus number of dups.
Like below (example)
Session Identifier dups
abc123 e8d971a4-ef33-4ea1-8627-f1213e4c67dc 2
abc345 1c62813f-7ec4-4968-b18b-d1eb8f4d9d26 3

Related

How to group by the amount of values in an array in postgresql

I have a posts table with few columns including a liked_by column which's type is an int array.
As I can't post the table here I'll post a single post's JSON structure which comes as below
"post": {
"ID": 1,
"CreatedAt": "2022-08-15T11:06:44.386954+05:30",
"UpdatedAt": "2022-08-15T11:06:44.386954+05:30",
"DeletedAt": null,
"title": "Pofst1131",
"postText": "yyhfgwegfewgewwegwegwegweg",
"img": "fegjegwegwg.com",
"userName": "AthfanFasee",
"likedBy": [
3,
1,
4
],
"createdBy": 1,
}
I'm trying to send posts in the order they are liked (Most Liked Posts). Which should order the posts according to the number of values inside the liked_by array. How can I achieve this in Postgres?
For a side note, I'm using Go lang with GORM ORM but I'm using raw SQL builder instead of ORM tools. I'll be fine with solving this problem using go lang as well. The way I achieved this in MongoDB and NodeJS is to group by the size of liked by array and add a total like count field and sort using that field as below
if(sort === 'likesCount') {
data = Post.aggregate([
{
$addFields: {
totalLikesCount: { $size: "$likedBy" }
}
}
])
data = data.sort('-totalLikesCount');
} else {
data = data.sort('-createdAt') ;
}
Use a native query.
Provided that the table column that contains the sample data is called post, then
select <list of expressions> from the_table
order by json_array_length(post->'likedBy') desc;
Unrelated but why don't you try a normalized data design?
Edit
Now that I know your table structure here is the updated query. Use array_length.
select <list of expressions> from public.posts
order by array_length(liked_by, 1) desc nulls last;
You may also wish to add a where clause too.

Cannot parse SQL result count from Logic App

I run this simple query in Logic App using the "Execute a SQL query (V2)" connector to find out if a number exists in my table.
select count(*) from users where user_number='724-555-5555';
If the number exist, I get this JSON , but somehow I cant parse it.
[
{
"": 1
}
]
Any idea how to simply retrieve 0 or 1 ?
Thanks
David
You need to add an explicit column name:
SELECT
count(*) AS cnt
FROM
users
WHERE
user_number = '724-555-5555';
That will give you this result:
[ { "cnt": 1 } ]
...which is valid JSON.

Retrieve the count of each record (id) with a condition within CosmosDB

I have a container within CosmosDB that houses items. I am needing to find out the count of how many records I have within my container with the conditions of: Source and Date
This is a sample JSON schema in which each of my records/items holds. Each record has a unique id and acts as a single count.
{
"id": "1111111111122222222233333333",
"feedback": {
"Source": "test"
"Date": "1980-10-15T00:04:34Z",
"Ser": "test",
"Count_Of_Comments": "1",
"Count_Of_Votes": "1"
}
The container within CosmosDB looks like something like this:
Goal:
**I wish to return, the numb*er of id records (or the count) based on the Source and the Date.
This is what I have tried (below), however this does not seem to work and I am wondering if I am missing something here. Any help or suggestions are appreciated.
SELECT VALUE COUNT(c.id), c.Source, c.Date
FROM C
Where Source == "test", AND Date == "1980-10-15T00:04:34Z"
As David comments,there are some syntax errors.Please try this sql:
SELECT value COUNT(c.id) FROM c Where c.feedback.Source = "test" AND c.feedback.Date = "1980-10-15T00:04:34Z"
If you need Source and Date,you can try this:
SELECT COUNT(c.id) AS Count,max(c.feedback.Source) as Source,max(c.feedback.Date) as Date
FROM c
Where c.feedback.Source = "test" AND c.feedback.Date = "1980-10-15T00:04:34Z"
By the way,both COUNT(c.id) AND COUNT(1) can achieve your goal in your situation.More detail about SQL Query,you can refer to this documentation.
Hope this can help you.

is it possible to nest an array_agg inside another array_agg

I have a SQL table message(application, type, action, date, ...) and I would like to get all the actions for a type and all the types for an application in a single query if possible.
So far I have managed to get the result in two separate queries like so:
select application, array_agg(distinct type) as types from message group by application;
application | types
--------------+----------------------------------------------------------------------------------------------------------------------------
app1 | {company,user}
app2 | {document,template}
app3 | {organization,user}
and the second query:
select type, array_agg(distinct action) as actions from message group by type;
type | actions
--------------------------------------+-----------------------------------------
company | {created,updated}
document | {created,tested,approved}
organization | {updated}
template | {deleted}
user | {created,logged,updated}
The most obvious single query I could come up with so far is just:
select application, type, array_agg(distinct action) from message group by application, type;
Which would require some programmatic processing to build the type array.
What I wanted to do was something theoretically like:
select application, array_agg(type, array_agg(action)) from message group by application, type which isn't possible as is but I feel there is a way to do it. I have also thought about nesting the second query into the first one but haven't found how to make it work yet.
demo:db<>fiddle
You can create tuples (records): (col1, col2). So if col2 is of type array, you created (text, text[]). These tuples can be aggregated as well into array of tuples:
SELECT
app,
array_agg((type, actions)) -- here is the magic
FROM (
SELECT
app,
type,
array_agg(actions) actions
FROM
message
GROUP BY app, type
) s
GROUP BY app
To get access, you have to explicitely define the record type at unnesting:
SELECT
*
FROM (
-- your query with tuples
)s,
unnest(types) AS t(type text, actions text[]) -- unnesting the tuple array
Nevertheless, as stated in the comments, maybe JSON may be a better approach for you:
demo:db<>fiddle
SELECT
app,
json_agg(json_build_object('type', type, 'actions', actions))
FROM (
SELECT
app,
type,
json_agg(actions) actions
FROM
message
GROUP BY app, type
) s
GROUP BY app
Result:
[{
"type": "company",
"actions": ["created","updated"]
},
{
"type": "user",
"actions": ["logged","updated"]
}]
Another possible JSON output:
demo:db<>fiddle
SELECT
json_agg(data)
FROM (
SELECT
json_build_object(app, json_agg(types)) as data
FROM (
SELECT
app,
json_build_object(type, json_agg(actions)) AS types
FROM
message
GROUP BY app, type
) s
GROUP BY app
) s
Result:
[{
"app1": [{
"company": ["created","updated"]
},
{
"user": ["logged","updated"]
}]
},
{
"app2": [{
"company": ["created"]
}]
}]

complex couchbase query using metadata & group by

I am new to Couchbase and kind a stuck with the following problem.
This query works just fine in the Couchbase Query Editor:
SELECT
p.countryCode,
SUM(c.total) AS total
FROM bucket p
USE KEYS (
SELECT RAW "p::" || ca.token
FROM bucket ca USE INDEX (idx_cr)
WHERE ca._class = 'backend.db.p.ContactsDo'
AND ca.total IS NOT MISSING
AND ca.date IS NOT MISSING
AND ca.token IS NOT MISSING
AND ca.id = 288
ORDER BY ca.total DESC, ca.date ASC
LIMIT 20 OFFSET 0
)
LEFT OUTER JOIN bucket finished_contacts
ON KEYS ["finishedContacts::" || p.token]
GROUP BY p.countryCode ORDER BY total DESC
I get this:
[
{
"countryCode": "en",
"total": 145
},
{
"countryCode": "at",
"total": 133
},
{
"countryCode": "de",
"total": 53
},
{
"countryCode": "fr",
"total": 6
}
]
Now, using this query in a spring-boot application i end up with this error:
Unable to retrieve enough metadata for N1QL to entity mapping, have you selected _ID and _CAS?
adding metadata,
SELECT
meta(p).id AS _ID,
meta(p).cas AS _CAS,
p.countryCode,
SUM(c.total) AS total
FROM bucket p
trying to map it to the following object:
data class CountryIntermediateRankDo(
#Id
#Field
val id: String,
#Field
#NotNull
val countryCode: String,
#Field
#NotNull
val total: Long
)
results in:
Unable to execute query due to the following n1ql errors:
{“msg”:“Expression must be a group key or aggregate: (meta(p).id)“,”code”:4210}
Using Map as return value results in:
org.springframework.data.couchbase.core.CouchbaseQueryExecutionException: Query returning a primitive type are expected to return exactly 1 result, got 0
Clearly i missed something important here in terms of how to write proper Couchbase queries. I am stuck between needing metadata and getting this key/aggregate error that relates to the GROUP BY clause. I'd be very thankful for any help.
When you have a GROUP BY query, everything in the SELECT clause should be either a field used for grouping or a group aggregate. You need to add the new fields into the GROUP by statement, sort of like this:
SELECT
_ID,
_CAS,
p.countryCode,
SUM(p.c.total) AS total
FROM testBucket p
USE KEYS ["foo", "bar"]
LEFT OUTER JOIN testBucket finished_contacts
ON KEYS ["finishedContacts::" || p.token]
GROUP BY p.countryCode, meta(p).id AS _ID, meta(p).cas AS _CAS
ORDER BY total DESC
(I had to make some changes to your query to work with it effectively. You'll need to retrofit the advice to your specific case.)
If you need more detailed advice, let me suggest the N1QL forum https://forums.couchbase.com/c/n1ql . StackOverflow is great for one-and-done questions, but the forum is better for extended interactions.