Selecting ID in a certain order specified within IN operator - sql

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;

Related

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)
);

Null values at the end of rows after INSERT INTO

I am currently trying to INSERT INTO my SQL database a row of 144 columns.
The problem is that the last 10 values of the new row are NULL while they are supposed to be float and int.
That's an example of what I have in my DB after the INSERT INTO :
First column
Before last column
Last column
1
NULL
NULL
That's the SQL request I am using
INSERT INTO "historic_data2"
VALUES (28438, 163, 156, 1, 'FIST 2', 91, 81, 82, 84, 90, 6, '2 Pts Int M', 'Offensive', 0, '91_81_82_84_90', 86, 85, 0, 36, 62, 24, 0, 132, 86, 0, 83, 0, 0, 0, 0, 42, 77, 24, 0, 173, 107, 0, 204, 0, 0, 0, 0, 42, 77, 24, 0, 173, 107, 0, 204, 0, 0, 0, 81, 62, 34, 23, 19, 45, 32, 18, 9, 19, 0.5555555555555556, 0.5161290322580645, 0.5294117647058824, 0.391304347826087, 1.0, 82, 54, 34, 18, 28, 49, 27, 17, 8, 28, 0.5975609756097561, 0.5, 0.5, 0.4444444444444444, 1.0, 302, 233, 132, 89, 69, 168, 116, 69, 35, 69, 0.5562913907284768, 0.4978540772532189, 0.5227272727272727, 0.39325842696629215, 1.0, 214, 161, 84, 73, 53, 119, 79, 39, 36, 53, 0.5560747663551402, 0.4906832298136646, 0.4642857142857143, 0.4931506849315068, 1.0, 717, 544, 298, 233, 173, 416, 285, 175, 97, 173, 0.5801952580195258, 0.5238970588235294, 0.587248322147651, 0.41630901287553645, 1.0, 466, 315, 183, 128, 151, 357, 233, 138, 91, 151, 0.7660944206008584, 0.7396825396825397, 0.7540983606557377, 0.7109375,1.0,112)
I can't figure out how to solve this issue. My guess would be that there is a hard limit on how much column you can insert at once but I don't know how to solve that.
Thank you in advance for your help

Kotlin add carriage return into multiline string

In Kotlin, when I build a multiline string like this:
value expected = """
|digraph Test {
|${'\t'}Empty1;
|${'\t'}Empty2;
|}
|""".trimMargin()
I see that the string lacks carriage return characters (ASCII code 13) when I output it via:
println("Expected bytes")
println(expected.toByteArray().contentToString())
Output:
Expected bytes
[100, 105, 103, 114, 97, 112, 104, 32, 84, 101, 115, 116, 32, 123, 10, 9, 69, 109, 112, 116, 121, 49, 59, 10, 9, 69, 109, 112, 116, 121, 50, 59, 10, 125, 10]
When some code I'm trying to unit test builds the same String via a PrintWriter it delineates lines via the lineSeparator property:
/*
* Line separator string. This is the value of the line.separator
* property at the moment that the stream was created.
*/
So I end up with a string which looks the same in output, but is composed of different bytes and thus is not equal:
Actual bytes
[100, 105, 103, 114, 97, 112, 104, 32, 84, 101, 115, 116, 32, 123, 13, 10, 9, 69, 109, 112, 116, 121, 49, 59, 13, 10, 9, 69, 109, 112, 116, 121, 50, 59, 13, 10, 125, 13, 10]
Is there a better way to address this during string declaration than splitting my multiline string into concatenated stringlets which can each be suffixed with char(13)?
Alternately, I'd like to do something like:
value expected = """
|digraph Test {
|${'\t'}Empty1;
|${'\t'}Empty2;
|}
|""".trimMargin().useLineSeparator(System.getProperty("line.separator"))
or .replaceAll() or such.
Does any standard method exist, or should I add my own extension function to String?
This did the trick.
System.lineSeparator()
Kotlin multiline strings are always compiled into string literals which use \n as the line separator. If you need to have the platform-dependent line separator, you can do replace("\n", System.getProperty("line.separator")).
As of Kotlin 1.2, there is no standard library method for this, so you should define your own extension function if you're using this frequently.

How to alias a list of values in SQL

I need to see if any of a set of columns contains a value in a list.
E.G
...
SELECT *
FROM Account
WHERE
NOT (
AccountWarningCode1 IN (02, 05, 15, 20, 21, 24, 31, 36, 40, 42, 45, 47, 50, 51, 52, 53, 55, 56, 62, 65, 66, 78, 79, 84, 110, 119, 120, 121, 125, 202)
OR AccountWarningCode2 IN (02, 05, 15, 20, 21, 24, 31, 36, 40, 42, 45, 47, 50, 51, 52, 53, 55, 56, 62, 65, 66, 78, 79, 84, 110, 119, 120, 121, 125, 202)
OR AccountWarningCode3 IN (02, 05, 15, 20, 21, 24, 31, 36, 40, 42, 45, 47, 50, 51, 52, 53, 55, 56, 62, 65, 66, 78, 79, 84, 110, 119, 120, 121, 125, 202)
...
)
The above does work, but what i'd like to do instead is alias the list some how so I don't repeat myself quite as much.
For example (this doesn't actually work)
WITH bad_warnings AS (02, 05, 15, 20, 21, 24, 31, 36, 40, 42, 45, 47, 50, 51, 52, 53, 55, 56, 62, 65, 66, 78, 79, 84, 110, 119, 120, 121, 125, 202)
SELECT *
FROM Account
WHERE
NOT (
AccountWarningCode1 IN bad_warnings
OR AccountWarningCode2 IN bad_warnings
OR AccountWarningCode3 IN bad_warnings
...
)
Is this possible in T-SQL?
Your second version is actually close. You can use a common table expression:
WITH bad_warnings(code) AS(
SELECT * FROM(VALUES
('02'), ('05'), ('15'), ('20'), ('21'), ('24'),
('31'), ('36'), ('40'), ('42'), ('45'), ('47'),
('50'), ('51'), ('52'), ('53'), ('55'), ('56'),
('62'), ('65'), ('66'), ('78'), ('79'), ('84'),
('110'), ('119'), ('120'), ('121'), ('125'), ('202')
) a(b)
)
SELECT *
FROM Account
WHERE
NOT (
AccountWarningCode1 IN (SELECT code FROM bad_warnings)
OR AccountWarningCode2 IN (SELECT code FROM bad_warnings)
OR AccountWarningCode3 IN (SELECT code FROM bad_warnings)
)
This is the way to define a derived table with your values as CTE.
WITH bad_warnings AS
(SELECT val FROM (VALUES(02),(05),(15),(20),(21),(24),(31),(36),(40),(42),(45),(47),(50),(51),(52),(53),(55),(56),(62),(65),(66),(78),(79),(84),(110),(119),(120),(121),(125),(202)) AS tbl(val)
)
SELECT *
FROM bad_warnings
You can use this as any table in your query.
Your check would be something like
WHERE SomeValue IN(SELECT val FROM badWarnings)
With NOT IN you would negate this list
Is this possible in T-SQL?
Yes, either use a table variable or a temporary table. Populate those inlist data in table variable and use it as many places within your procedure you want.
Example:
declare #inlist1 table(elem int);
insert into #inlist1
select 02
union
select 05
union
select 15
union
select 20
union
select 21
union
select 24
Use it now
WHERE
NOT (
AccountWarningCode1 IN (select elem from #inlist1)
(OR)
You can as well perform a JOIN operation saying
FROM Account a
JOIN #inlist1 i ON a.AccountWarningCode1 = i.elem
You can do it like this:
with bad_warnings as
(select '02'
union
select '15'
etc
)
select * from account
where not
(AccountWarningCode1 IN (SELECT code FROM bad_warnings
etc)

PG:GroupingError only appearing on production

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.