Insert many-to-many relations in one transaction using Korma - sql

I have 2 models with many-to-many relationship like the next:
(declare organisations)
(defentity users
(many-to-many organisations :users_organisations
{:lfk :user_id, :rfk :organisation_id}))
(defentity organisations
(many-to-many users :users_organisations
{:lfk :organisation_id, :rfk :user_id}))
(defentity users-organisations
(table :users_organisations))
I want to insert rows into both models and make a relationship record in the same transaction
(transaction
(let [usr (insert users (values {:email "john#mail.me"}))
org (insert organisations (values {:title "My Co."}))]
(insert users-organisation
(values {:user_id (:id usr)
:organisation_id (:id org)}))))
Unfortunately, it doesn't work this way. None of insertions into users or organisations work. Is it possible to do something like that in Korma?
What I try to achieve is something like the next Postgresql statement:
WITH new_user AS (
INSERT INTO users (email)
VALUES ('john#mail.me')
RETURNING id
), new_org AS (
INSERT INTO organisations (title)
VALUES ('My Co.')
RETURNING id
)
INSERT INTO users_organisations (user_id, organisation_id)
VALUES ((SELECT id FROM new_user), (SELECT id FROM new_org))
RETURNING *;
Thanks in advance for any help!

Related

Foreach insert statement based on where clause

I have a scenario where I have thousands of Ids (1-1000), I need to insert each of these Ids once into a table with another record.
For example, UserCars - has columns CarId and UserId
I want to INSERT each user in my Id WHERE clause against CarId 1.
INSERT INTO [dbo].[UserCars]
([CarId]
,[UserId])
VALUES
(
1,
**My list of Ids**
)
I'm just not sure of the syntax for running this kind of insert or if it is at all possible.
As you write in the comments that my list of Ids is coming from another table, you can simply use select into with a select clause
See this for more information
insert into UserCars (CarID, UserID)
select CarID, UserID
from othertable
In the select part you can use joins and whatever you need, complex queries are allowed as long as the columns in the result match the columns (CarID, UserID)
or even this to keep up with your example
insert into UserCars (CarID, UserID)
select 1, UserID
from dbo.User
if your data exists on a file, you can use BULK INSERT command, for example:
BULK INSERT UserCars
FROM '\\path\to\your\folder\users-cars.csv';
Just make sure to have the same columns structure both in the file and in the table (e.g. CarId,UserId).
Otherwise, follow #GuidoG comment to insert your data from another table:
insert into UserCars (CarID, UserID) select CarID, UserID from othertable

postgres insert into multiple tables after each other and return everything

Given postgres database with 3 tables:
users(user_id: uuid, ...)
urls(slug_id:int8 pkey, slug:text unique not null, long_url:text not null)
userlinks(user_id:fkey users.user_id, slug_id:fkey urls.slug_id)
pkey(user_id, slug_id)
The userlinks table exists as a cross reference to associate url slugs to one or more users.
When a new slug is created by a user I'd like to INSERT into the urls table, take the slug_id that was created there, INSERT into userlinks with current users ID and slug_id
Then if possible return both results as a table of records.
Current users id is accessible with auth.uid()
I'm doing this with a stored procedure in supabase
I've gotten this far but I'm stuck:
WITH urls_row as (
INSERT INTO urls(slug, long_url)
VALUES ('testslug2', 'testlong_url2')
RETURNING slug_id
)
INSERT INTO userlinks(user_id, slug_id)
VALUES (auth.uid(), urls_row.slug_id)
--RETURNING *
--RETURNING (urls_record, userlinks_record)
Try this :
WITH urls_row as (
INSERT INTO urls(slug, long_url)
VALUES ('testslug2', 'testlong_url2')
RETURNING slug_id
), userlink_row AS (
INSERT INTO userlinks(user_id, slug_id)
SELECT auth.uid(), urls_row.slug_id
FROM urls_row
RETURNING *
)
SELECT *
FROM urls_row AS ur
INNER JOIN userlink_row AS us
ON ur.slug_id = us.slug_id

Inserting into table values found from previous query

I have table, let's say 'ROLEE'., which contain columns ROLE, ACCESSENTRY. I need to find first rows that ACCESSENTRY is equal to 'A' and for these rows insert into that table new rows with fetched 'ROLE' and given ACCESSENTRY.
So let's say within this query:
select role from ROLEE where ACCESSENTRY='A'
I get 2 rows with values: ADMIN, USER
and for these roles (ADMIN, USER) I need to insert
INSERT INTO ROLEE
values ('ADMIN', 'ACCESS')
INSERT INTO ROLEE
values ('USER', 'ACCESS')
I tried with these, but it does not work:
INSERT INTO ROLEE
values (role, 'ACCESS') where role in (
select role from ROLEE where ACCESSENTRY='A')
Please use below insert statement,
insert into ROLEE (select role, 'ACCESS' from ROLEE where ACCESSENTRY='A');
The right way is to specify the column names,
insert into ROLEE(column1, column2) (select role, 'ACCESS' from ROLEE where ACCESSENTRY='A'); -- Provide the respective column names in colum1 and column2

Many-to-many relationship to determine if user has liked a post

I have a table that contains all of the posts. I also have a table where a row is added when a user likes a post with foreign keys user_id and post_id.
I want to retrieve a list of ALL of the posts and whether or not a specific user has liked that post. Using an outer join I end up getting some posts twice. Once for user 1 and once for user 2. If I use a WHERE to filter for likes.user_id = 1 AND likes.user_id is NULL I don't get the posts that are only liked by other users.
Ideally I would do this with a single query. SQL isn't my strength, so I'm not even really sure if a sub query is needed or if a join is sufficient.
Apologies for being this vague but I think this is a common enough query that it should make some sense.
EDIT: I have created a DB Fiddle with the two queries that I mentioned. https://www.db-fiddle.com/f/oFM2zWsR9WFKTPJA16U1Tz/4
UPDATE: Figured it out last night. This is what I ended up with:
SELECT
posts.id AS post_id,
posts.title AS post_title,
CASE
WHEN EXISTS (
SELECT *
FROM likes
WHERE posts.id = likes.post_id
AND likes.user_id = 1
) THEN TRUE
ELSE FALSE END
AS liked
FROM posts;
Although I was able to resolve it, thanks to #wildplasser for his answer as well.
Data (I needed to change it a bit, because one should not assign to serials):
CREATE TABLE posts (
id serial,
title varchar
);
CREATE TABLE users (
id serial,
name varchar
);
CREATE TABLE likes (
id serial,
user_id int,
post_id int
);
INSERT INTO posts (title) VALUES ('First Post');
INSERT INTO posts (title) VALUES ('Second Post');
INSERT INTO posts (title) VALUES ('Third Post');
INSERT INTO users (name) VALUES ('Obama');
INSERT INTO users (name) VALUES ('Trump');
INSERT INTO likes (user_id, post_id) VALUES (1, 1);
INSERT INTO likes (user_id, post_id) VALUES (2, 1);
INSERT INTO likes (user_id, post_id) VALUES (2, 2);
-- I want to retrieve a list of ALL of the posts and whether or not a specific user has liked that post
SELECT id, title
, EXISTS(
--EXISTS() yields a boolean value
SELECT *
FROM likes lk
JOIN users u ON u.id = lk.user_id AND lk.post_id=p.id
WHERE u.name ='Obama'
) AS liked_by_Obama
FROM posts p
;
Results:
id | title | liked_by_obama
----+-------------+----------------
1 | First Post | t
2 | Second Post | f
3 | Third Post | f
(3 rows)
As far as I understand, you have two tables such as post table which includes all post from different users and a like table with user.id and post id. if you want to retreive only posts then
select * from posts
if you need user information as well, which is present in user table then you can do below.
select user.user_name, post.postdata from user,post where post.userid=user.userid
in above query, user_name is a column name in user table and postdata is a column in post table.

Dynamically Insert into table while checking if the record already exists

I had some doubts on dynamic insertion of data while doing an insert statement so just wanted to get some assistance from you guys. I have to do multiple insert statements say around 1500 records based on 2 different criteria's below is just a sample of 1 insert statement.
Now while doing an insert statement I want to dynamically assign the USERID's and ROLEid's the 2 columns which you can see in the query below.
So for example where userid IN (500 different userid) and role id in (100 different) ones.
Insert into userrolelist (Userid, Roleid, IsDefault, EffectiveStart,
EffectiveEnd, Clientid, LastmodifiedUserId, LastmodifiedTimestamp)
Values (161514,1011,1,'2016-01-21 00:00:00.001',Null,16785,0,'2016-01-21
00:00:00.001')
I am sure there is a way to do dynamic insertion based on 2 different criteria's I am just confused as to how can I achieve that. Mainly also because for each criteria before insertion I need to check if that userid + roleid combination already exists in the table. Because if I dont check it and still do an insert it will throw an error because there is a constraint based on the 2 fields.
Any help on this matter would be appreciated. Please let me know if the question is not very clear and i can add a bit more explanation if required. Thank you.
You don't say where your lists of user IDs and role IDs are coming from, but because you specify different numbers for each of them, I assume that they are separate lists, rather than a single list of pairs. And I assume that they are stored in tables named userlist and rolelist, respectively. Then you can do the insert as follows:
insert into userrolelist
(Userid, Roleid, IsDefault, EffectiveStart, EffectiveEnd,
Clientid, LastmodifiedUserId, LastmodifiedTimestamp)
select
userid, roleid,
1,'2016-01-21 00:00:00.001',Null,16785,0,
'2016-01-21 00:00:00.001'
from
(select userid, roleid
from userlist
cross join rolelist
) as userrole
where
not exists (select 1 from userrolelist as ur where ur.userid=userrole.userid and ur.roleid=userrole.roleid);
The subquery constructs a list of all possible pairs of users and roles, so if you already have a list of pairs, you can simply use that in place of the subquery.