PG:GroupingError only appearing on production - sql

I have a model "Playlist" which has_many and belongs_to another model "User", through an intermediary model "PlaylistUser".
I have code that, for a given Playlist #playlist, lists all the other Playlists that share a User with #playlist, ordered by how many they share.
This code works perfectly on development, but on production, it's throwing this error:
PG::GroupingError: ERROR: column "playlists.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "playlists".* FROM "playlists" INNER JOIN "playlist...
^
: SELECT "playlists".* FROM "playlists" INNER JOIN "playlist_users" ON "playlist_users"."playlist_id" = "playlists"."id" INNER JOIN "users" ON "users"."id" = "playlist_users"."user_id" WHERE (NOT (playlists.id = 30 OR playlists.id = 41)) AND "users"."id" IN (45, 89, 71, 117, 115, 173, 177, 180, 161, 220, 223, 199, 221, 239, 204, 205, 206, 207, 211, 261, 282, 284, 286, 251, 252, 255, 310, 311, 315, 318, 307, 362, 319, 306, 289, 316, 305, 321, 322, 330, 333, 292, 294, 304, 300, 340, 341, 342, 343, 405, 406, 410, 408, 409, 407, 413, 416, 417, 418, 425, 427, 392, 401, 403, 445, 446, 449, 450, 379, 456, 451, 454, 459, 437, 442, 444, 496, 501, 518, 548, 549, 533, 553, 1112, 1113, 1459, 455, 348, 1458, 242, 1275, 151, 1890, 336, 203, 404, 166, 453, 114, 157, 285, 448, 447, 443, 550, 2167, 2168, 287, 320, 293, 65, 2098, 2097, 2099, 387, 3, 2175, 2170, 2174, 2182, 2171, 438, 2180, 2181, 2169, 2176, 347, 2429, 2177, 2445, 2178, 2447, 58, 2480, 390, 452, 554, 555, 313, 92, 275, 335, 428, 167, 302, 2173, 1538) GROUP BY playlists.id ORDER BY count(*) desc
Why would my query be working on development but not on production?
Query
#playlist_ids = #playlist.user_ids
#more_playlists = Playlist.joins(:users).where.not('playlists.id = ? OR playlists.id = ?', 30, 41).where(users: {id: #playlist_ids}).group('playlists.id').order('count(*) desc')
Assocations:
class Playlist < ActiveRecord::Base
has_many :playlist_users
has_many :users, :through => :playlist_users
end
class PlaylistUser < ActiveRecord::Base
belongs_to :playlist
belongs_to :user
end
class User < ActiveRecord::Base
has_many :playlist_users
has_many :playlists, :through => :playlist_users
end
UPDATE
This is pretty strange, I added Playlist.name to the GROUP BY as per trincot's suggestion:
#playlist_ids = #playlist.user_ids
Playlist.select('playlists.id, playlists.name')
.joins(:playlist_users)
.where('playlists.id NOT IN (30, 41)')
.where(playlist_users: {user_id: #playlist_ids})
.group('playlists.id, playlists.name')
.order('count(*) desc')
But I'm getting back a similar error, except now it's telling me I have to include thePlaylist attribute subject_id in the GROUP BY clause:
PG::GroupingError: ERROR: column "playlists.subject_id" must appear in the GROUP BY clause or be used in an aggregate function
But I didn't reference subject_id literally anywhere in my query, or even in the model, controller, or view for the page. Why on earth would that column even be involved in this?

Your statement is not valid according to the PostgreSQL documentation:
When GROUP BY is present, it is not valid for the SELECT list expressions to refer to
ungrouped columns except within aggregate functions, since there would be more than one
possible value to return for an ungrouped column.
If you say it works in your development environment, it must mean that environment has another database engine (version) running.
You should use a statement like this, where the list of fields in the SELECT clause is the same as the list given in the GROUP BY clause:
SELECT playlists.id, playlists.name, ...
FROM playlists
INNER JOIN playlist_users ON playlist_users.playlist_id = playlists.id
WHERE playlists.id NOT IN (30, 41)
AND playlist_users.user_id IN (your_long_list_comes_here)
GROUP BY playlists.id, playlists.name, ...
ORDER BY count(*) desc
Note that you don't actually need to join the users table for the result of your interest, so I removed it and replaced the test on user_id accordingly. Also, the condition on the playlists.id is expressed more concise using the IN operator.
The corresponding Active Record query would be:
Playlist.joins(:playlist_users)
.where('playlists.id NOT IN (30, 41)')
.where(playlist_users: {user_id: #playlist_ids})
.select('playlists.id, playlists.name')
.group('playlists.id, playlists.name')
.order('count(*) desc')
You have to add any other fields you need in both the select and group arguments.

Related

Delete ranges of id's

I have this huge SQL query which I would like to reduce:
DELETE
FROM users
WHERE id in (754, 755, 756, 757, 758, 759, 795, 796, 797, 798, 799, 765,
766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794);
I tried:
DELETE
FROM users
WHERE id => 754 AND id <= 759
AND id => 795 AND id <= 799
AND id => 765 AND id <= 794;
But I get error:
ERROR: syntax error at or near "=>"
Position: 42
Do you know how I can fix this issue?
You could do it this way:
DELETE
FROM users
WHERE
id between 754 and 759
OR id between 765 and 799
use >= operator
example
delete from users where id >= 754

Separate user role in SQL

I have a table called user_role_link where the column are userid, roleid, bitlive and bitdeleted.
This table links to the dbo.user_role where in here I have columns roleid, DescriptionRole
I want to extract all the users with introleid in (256, 308, 313) but not to be part of this roles: introleid NOT IN (225, 228, 229, 230, 231, 232, 233, 236) normally if you have on of this you could have these ones (256, 308, 313).
So what I am looking to achieve is to remove these roles from the users (256, 308, 313) where they don't have the main one (225, 228, 229, 230, 231, 232, 233, 236)
By mistake someone granted to these users the roles without having the parent one.
My query is like this
select distinct intuserid
from user_role_link
where introleid in (256, 308, 313, 314, 484, 485)
and introleid NOT IN (225, 228, 229, 230, 231, 232, 233, 236, 237, 239, 240, 241, 242)
and bitLive = 1
and bitDeleted = 0
Please can you let me know how this can be improved.
So you want to remove 3 roles from users, but only when any of those other roles don't exist for them.
Then you could use a NOT EXISTS
DELETE
FROM user_role_link ur1
WHERE roleid IN (256, 308, 313)
AND bitLive = 1
AND bitDeleted = 0
AND NOT EXISTS (
SELECT 1
FROM user_role_link ur2
WHERE ur2.userid = ur1.userid
AND ur2.roleid IN (225, 228, 229, 230, 231, 232, 233, 236)
);

Julia and dbscan clustering: how extract elements from resulting structure?

Warning: this is from a julia n00b!
After performing dbscan on a point coordinate array in Julia. (Note that this is not the 'distance based method' that returns 'assignments' as part of the result structure, but the 'adjacency list' method). Documentation here. I attempt to access the vector containing the indices, but I am at a loss when trying to retrieve the members of individual clusters:
dbr = dbscan(pointcoordinates, .1, min_neighbors = 10, min_cluster_size = 10)
13-element Array{DbscanCluster,1}:
DbscanCluster(17, [4, 12, 84, 90, 94, 675, 676, 737, 873, 965], [27, 108, 177, 880, 954, 1050, 1067])
DbscanCluster(10, Int64[], [46, 48, 51, 57, 188, 225, 226, 228, 270, 542])
DbscanCluster(11, [48, 51, 228], [46, 49, 57, 188, 225, 226, 270, 542])
DbscanCluster(14, [418, 759, 832, 988, 1046], [830, 831, 855, 865, 989, 991, 996, 1021, 1070])
DbscanCluster(10, Int64[], [624, 654, 664, 803, 805, 821, 859, 987, 1057, 1069])
It is easy to retrieve a single cluster from the array:
> dbr[1]
DbscanCluster(17, [4, 12, 84, 90, 94, 675, 676, 737, 873, 965], [27, 108, 177, 880, 954, 1050, 1067])
But how do i get the stuff inside DBscanCluster?
a = dbr[1]
DbscanCluster(17, [4, 12, 84, 90, 94, 675, 676, 737, 873, 965], [27, 108, 177, 880, 954, 1050, 1067])
In [258]:
a[1]
MethodError: no method matching getindex(::DbscanCluster, ::Int64)
Thank you for your help, and sorry if I am missing something glaring!
What makes you say that DbscanCluster is a child of array?
julia> DbscanCluster <: AbstractArray
false
You might be confused by Array{DbscanCluster,1} in your result, but this just tells you that the object returned by the dbscan call is an Array the elements of which are of type DbscanCluster - this does not tell you anything about whether those elements themselves are subtypes of Array.
As for how to get the indexes, the docs for DbscanResult show that the type has three fields:
seeds::Vector{Int}: indices of cluster starting points
assignments::Vector{Int}: vector of clusters indices, where each point was assigned to
counts::Vector{Int}: cluster sizes (number of assigned points)
each of which you can access with dot notation by doing e.g. drb[1].assignments.
If you want to get say the counts for all the 13 clusters in your results, you can broadcast getproperty like so:
getproperty.(drb, :counts)
Note that counts does not exist for in the case of the "adjacency lists" method of dbscan, one can use:
getproperty.(drb, :core_indices)

Postgresql Grouping Error refers to a column that was never referenced in the query

I have a model "Playlist" which has_many and belongs_to another model "User", through an intermediary model "PlaylistUser". "Playlist" has several attributes including id, name, and subject_id.
I'm trying to get this query to work:
#playlist_ids = #playlist.user_ids
#more = Playlist.select('playlists.id, playlists.name')
.joins(:playlist_users)
.where('playlists.id NOT IN (30, 41)')
.where(playlist_users: {user_id: #playlist_ids})
.group('playlists.id, playlists.name')
.order('count(*) desc')
which, for a given Playlist #playlist, is supposed to list all the other Playlists that share a User with #playlist, ordered by how many they share.
It works on Postgres 9.4, but with Postgres 8.4 it returns this error:
PG::GroupingError: ERROR: column "playlists.subject_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "playlists".* FROM "playlists" INNER JOIN "playlist...
^
: SELECT "playlists".* FROM "playlists" INNER JOIN "playlist_users" ON "playlist_users"."playlist_id" = "playlists"."id" INNER JOIN "users" ON "users"."id" = "playlist_users"."user_id" WHERE (NOT (playlists.id = 30 OR playlists.id = 41)) AND "users"."id" IN (45, 89, 71, 117, 115, 173, 177, 180, 161, 220, 223, 199, 221, 239, 204, 205, 206, 207, 211, 261, 282, 284, 286, 251, 252, 255, 310, 311, 315, 318, 307, 362, 319, 306, 289, 316, 305, 321, 322, 330, 333, 292, 294, 304, 300, 340, 341, 342, 343, 405, 406, 410, 408, 409, 407, 413, 416, 417, 418, 425, 427, 392, 401, 403, 445, 446, 449, 450, 379, 456, 451, 454, 459, 437, 442, 444, 496, 501, 518, 548, 549, 533, 553, 1112, 1113, 1459, 455, 348, 1458, 242, 1275, 151, 1890, 336, 203, 404, 166, 453, 114, 157, 285, 448, 447, 443, 550, 2167, 2168, 287, 320, 293, 65, 2098, 2097, 2099, 387, 3, 2175, 2170, 2174, 2182, 2171, 438, 2180, 2181, 2169, 2176, 347, 2429, 2177, 2445, 2178, 2447, 58, 2480, 390, 452, 554, 555, 313, 92, 275, 335, 428, 167, 302, 2173, 1538) GROUP BY playlists.id, playlists.name ORDER BY count(*) desc
But I'm not referencing the column subject_id anywhere in my query, or anywhere in the view, controller, or model for the page I'm on.
Why would that column have anything to do with whether my query works or not?
Assocations:
class Playlist < ActiveRecord::Base
has_many :playlist_users
has_many :users, :through => :playlist_users
end
class PlaylistUser < ActiveRecord::Base
belongs_to :playlist
belongs_to :user
end
class User < ActiveRecord::Base
has_many :playlist_users
has_many :playlists, :through => :playlist_users
end
Maybe you are not referencing subject_id explicitly but your result query uses:
SELECT "playlists".* FROM "playlists"
And because of the wildcard * you are getting all of the columns in playlist, which includes playlists.subject_id.
You will have to add that column to the group_by clause as well as any others that are grabbed by the wildcard SELECT.

Selecting ID in a certain order specified within IN operator

I would like to try to select a certain set of numbers in a particular order, for use with loops.
SELECT ID
FROM filter
WHERE id in (87, 97, 117, 52, 240, 76, 141, 137, 157, 255, 186, 196, 133,
175, 153, 224, 59, 205, 65, 47, 105, 80, 113, 293, 161, 145,
192, 149, 231, 91, 101, 109, 215, 121, 125, 64, 41, 291, 367,
388, 391, 462, 467)
Doing this returns results sorted by ID, rather than in the order I specified. In most other similar questions a preferred answer was using CASE for particular entries, but what about selecting hundreds of records in a predetermined order?
If you have hundreds of items, then use a derived table, such as:
select f.id
from filter f join
(values(1, 87), (2, 97), (3, 117), . . .) as v(ord, id)
on f.id = v.id
order by ord;