I am trying to order by a field that is present sometimes and other times its not. Example data:
[
{ Name: Jeff, RegisteredUser: true },
{ Name: Jane },
{ Name: Jill, RegisteredUser: true },
]
My query is like so:
SELECT a.*
FROM table a
WHERE AND a.DocType = "User"
ORDER BY Lower(a.RegisteredUser) ASC
However when I use the query above it doesn't order by properly at all (basically does nothing).
It does order. Please note LOWER on MISSING is MISSING and placed at first,
LOWER on non-string value is NULL (because LOWER can be done only on string) which is placed after MISSING. In duplicated values can be placed any order with in duplicates, to avoid that provide more ORDER BY expressions. Checkout https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/orderby.html
You can remove LOWER because no lower is required on boolean field.
SELECT a.*
FROM table a
WHERE AND a.DocType = "User"
ORDER BY a.RegisteredUser ASC;
Related
I have the following json structure on my Postgres. The table is named "customers" and the field that contains the json is named "data"
{
customerId: 1,
something: "..."
list: [{ nestedId: 1, attribute: "a" }, { nestedId: 2, attribute: "b" }]
}
I'm trying to query all customers that have an element inside the field "list" with nestedId = 1.
I accomplished that poorly trough the query:
SELECT data FROM customers a, jsonb_array_elements(data->'list') e WHERE (e->'nestedId')::int = 1
I said poorly because since I'm using jsonb_array_elements on the FROM clausule, it is not used as filter, resulting in a seq scan.
I tried something like:
SELECT data FROM customers where data->'list' #> '{"nestedId": 1, attribute: "a"}'::jsonb
But it does not return anything. I imagine because the "list" field is seen as an array and not as each type of my records.
Any ideas how to perform that query filtering nestedId on the WHERE condition?
Try this query:
SELECT data FROM customers where data->'list' #> '[{"nestedId": 1}]';
This query will work in Postgres 9.4+.
I currently have the below query which is getting everything that has id = a certain value, but I need it to get only items that have a their column (called Uid) value appear more than once in the table.
Basically I need to filter out items with a unique Uid column value from the result of the below query
models.table.findAll({
where:{
id: req.params.id
}
})
So I believe the SQL query you're looking for would be
SELECT id, uid, count(*) FROM table
WHERE id = :id
GROUP BY id, uid
HAVING count(uid) > 1;
And in Sequelize it would be:
models.table.findAll({
where: { id: req.params.id },
group: ['id', 'uid'],
having: [sequelize.literal('count(?) > ?)', 'uid', 1]
})
Not entirely sure if that is the right syntax for Sequelize. Also look at sequelize.fn() and sequelize.col().
I have setup a schema where I associate two different entities: Users and Brands. This association is stored in the document UserBrand. A user may have multiple brands, and in each UserBrand document, the information there contained is different.
Here is an example of three documents:
{
type: "UserBrand",
userId: "x",
brandId: 1,
value: 100
}
{
type: "UserBrand",
userId: "x",
brandId: 2,
value: 50
}
{
type: "UserBrand",
userId: "y",
brandId: 1,
value: 150
}
As you see, user 'x' follows multiple brands. How can I get the sum of the values grouped by user, while fetching the user information as well?
So far I am able to join both document types (User and UserBrand) through this query:
SELECT ub.*, u.name FROM bucket as ub JOIN bucket as u ON KEYS "User_" || ub.userId WHERE ub.type="UserBrand" AND u.type="User" AND (ub.brand=1 OR ub.brand=2)
but I cannot seem to group the records and sum the values for a single user. Is it possible to do so on a single query?
If possible, the end result should be something like:
{
type: "UserBrand",
name: "name1',
userId: "x",
brandId: 1,
value: 150
}
{
type: "UserBrand",
name: "name2',
userId: "y",
brandId: 1,
value: 150
}
Why are you using 'join' instead of simply 'group by' and aggregation? If I wanted to sum the values for each distinct userId, I would write a query as follows:
select userId, sum(value) from bucket group by userId;
Note that when using 'group by', every field in the select list must be either part of the 'group by' list (userId above) or an aggregation expression (like sum(value) above). But what if you want to include the field 'name' in the result? If you know that 'name' always has the same value for a given id, you could use an aggregation function like 'max' or 'min' to bring up the value (since max of a set of identical values will be any of the values):
select userId, max(name), sum(value) from bucket group by userId;
For a field like 'brandId', which seems to have different values, you'd want to use an aggregation function like 'array_agg', which will take all the different values of 'brandId' and put them in an array. E.g.,
select userId, max(name), sum(value), array_agg(distinct brandId) from bucket group by userId;
In my schema, User hasMany GameSession, GameSession hasMany Game.
For a particular user, I'm trying to select the most recent game session which has three games, each of which has a non-null score.
This comment looks like it does almost exactly what I want, but it's not working for me. It suggests this code:
ModelA.findAll({
include: [ModelB],
having: 'count(ModelB.id) > 0'
});
I think the above comment might be out of date, because unless I wrap the having clause in an array I get Error: where: "raw query" has been removed, please use where ["raw query", [replacements]].
So I have this JS:
user.getGameSessions({
include: [
{
model: models.Game,
where: {
score: {
$ne: null
}
}
}
],
having: ['count(Games.id) = 3'],
order: [['updatedAt', 'DESC']],
limit: 1
}).then(function(gameSessions) {
res.json(gameSessions);
});
And this is the query it is making:
SELECT
`GameSession`.*,
`Games`.`id` AS `Games.id`,
...
FROM (
SELECT
`GameSession`.`id`,
...
`GameSession`.`UserId`
FROM `GameSessions` AS `GameSession`
WHERE `GameSession`.`UserId` = 33 AND (
SELECT `GameSessionId`
FROM `Games` AS `Game`
WHERE (
`Game`.`GameSessionId` = `GameSession`.`id`
AND `Game`.`score` IS NOT NULL
)
LIMIT 1
) IS NOT NULL
HAVING count(Games.id) = 3
ORDER BY `GameSession`.`updatedAt` DESC
LIMIT 1
) AS `GameSession`
INNER JOIN `Games` AS `Games`
ON `GameSession`.`id` = `Games`.`GameSessionId`
AND `Games`.`score` IS NOT NULL
ORDER BY `GameSession`.`updatedAt` DESC;
But running this gives the following error: SequelizeDatabaseError: ER_BAD_FIELD_ERROR: Unknown column 'Games.id' in 'having clause'. I've also tried using singular Game.id in the having clause, since I'm not always certain when to use the plural and when to use the singular, and I get a similar error.
What am I doing wrong? How can I make this work?
Is it possible to limit an include?
Currently no. I think there's a feature request open
for it (although i couldn't find it with a cursory search. It's not
trivial to implement since it requires a join on a subquery.
I think because MySQL is case sensitive your Games.id is Games.Id or Games.ID.
If I were you to save yourself some grief in the future, just make every table and column uppercase or all lower case. Don't do camel casing or things like that! It becomes really hard to debug.
So your code here is probably:
having: 'count(Games.id) = 3',
should be:
having: 'count(Games.Id) = 3',
Edit:
Have you tried putting backticks around your count? Like this:
having: 'count(`Games`.`id`) = 3',
I have 2 models simplified for the sake of this example (Domain, Visit) and I want to select the last visit timestamp for a given domain via column property
Domain.last_visit = db.column_property(
db.select(
[ db.func.ifnull( Visit.timestamp, 0 ) ],
Visit.domain_id == Domain.id
).order_by(Visit.timestamp.desc()).limit(1).correlate(Visit.__table__).label('domain_last_visit'),
deferred = True
)
My problem is that the value always returns NULL instead of 0. I'm pretty sure it's because I don't know how to select the record I want and I placed that limit over there.
Any ideas what am I doing wrong?
Your IFNULL will only fallback to the 0 in case you have rows in Visit which have timestamp = NULL. But it does not cover the case when a Domain has no corresponding Visit records yet.
One way to achive that would be to use MAX aggregate instead of ORDER BY ... DESC and appy IFNULL on the result:
Domain.last_visit = column_property(
select( [ func.ifnull(func.max( Visit.timestamp ), 0) ],
Visit.domain_id == Domain.id
).correlate_except(Visit).label('domain_last_visit'),
#deferred = True
)
Please note usage of correlate_except instead of correlate found in your code, which does not properly filter the results.
You might also consider Hybrid Attributes.