Postgres: хотите ВЫБРАТЬ данные, когда пользователь существует, иначе ВСТАВИТЬ пользователя
Все еще осваиваю PostgreSQL (используя PostgreSQL-12, поэтому любые советы очень приветствуются.
У меня есть приложение, которое позволяет пользователю сохранять и создавать списки воспроизведения песен.
Мои таблицы: пользователи, плейлисты, песни. Затем у меня есть две соединительные таблицы: user_playlist, playlist_song.
У меня есть запрос, который при задании идентификатора пользователя возвращает все песни из первого списка воспроизведения этого пользователя (по умолчанию приложение использует первый список воспроизведения при входе в систему), и в настоящее время он работает так, как я хочу.
Моя следующая проблема, которую нужно решить, заключается в том, что я хочу теперь объединить этот запрос со вторым, который добавит идентификатор пользователя в таблицу пользователей, если он в настоящее время не существует.
Таким образом, потоком будет вход пользователя в систему, а затем при входе в мою базу данных будет отправлен идентификатор пользователя. В моей базе данных я хочу проверить, существует ли этот идентификатор пользователя уже, если я хочу, чтобы запрос SELECT, возвращающий песни, выполнялся, но если этот идентификатор пользователя не существует, я хочу вставить идентификатор пользователя в свою таблицу пользователей
Я читал о 10 решениях Stackru, пытаясь настроить их так, чтобы они работали на меня, но мне не повезло. Я не уверен, стоит ли публиковать все то, что я уже пробовал, или нет.
$$ BEGIN
IF EXISTS (SELECT 1 FROM users WHERE userid = '1') THEN
SELECT
s.songid,
s.title,
s.artists,
s.album,
s.year,
s.duration,
s.url,
ps.songOrder
FROM
playlist_song ps
JOIN
songs s
ON
ps.songid = s.songid
JOIN
playlists p
ON
ps.playlistid = p.playlistid
WHERE
p.playlistid = (
SELECT
p.playlistid
FROM
user_playlist up
JOIN
playlists p
ON
up.playlistid = p.playlistid
JOIN
users u
ON
up.userid = u.userid
WHERE
u.userid = '1'
LIMIT 1
)
ORDER BY ps.songOrder;
ELSE
INSERT INTO users (userid, username) VALUES ('1', 'Haley')
ON CONFLICT DO NOTHING;
END IF;
END $$;
Это ошибка, которую он сейчас выдает мне, когда я тестирую его в администраторе PG:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL statement
SQL state: 42601
Затем я добавил RETURN в свой SELECT, и ошибка изменилась на
LINE 5: RETURN (SELECT
^
SQL state: 42804
Character: 98
Добавление RETURN QUERY дало ошибку: Cannot use return query in a non-setof function
Добавление RETURN SETOF дало ошибку: RETURN не может иметь параметр в функции, возвращающей void
Я застрял на этом полтора дня, и на данный момент я не хочу разбивать его на несколько обращений к базе данных, если это невозможно (моя гордость должна раздавить этого педераста)
Не могу сказать, насколько будет оценена ваша помощь! заранее спасибо
РЕДАКТИРОВАТЬ: вот мои таблицы
CREATE TABLE IF NOT EXISTS users (
userid TEXT NOT NULL,
username TEXT NOT NULL,
CONSTRAINT u_id_pk PRIMARY KEY (userid)
);
CREATE TABLE IF NOT EXISTS playlists (
playlistid SERIAL NOT NULL,
playlistname TEXT NOT NULL,
CONSTRAINT p_id_pk PRIMARY KEY (playlistid)
);
CREATE TABLE IF NOT EXISTS songs (
songid SERIAL NOT NULL,
url TEXT,
href TEXT,
title TEXT,
artists TEXT,
album TEXT,
year integer,
duration integer,
CONSTRAINT s_pk PRIMARY KEY (songid)
);
CREATE TABLE IF NOT EXISTS user_playlist (
userid TEXT,
playlistid INTEGER,
CONSTRAINT u_up_fk FOREIGN KEY (userid) REFERENCES users(userid),
CONSTRAINT p_up_fk FOREIGN KEY (playlistid) REFERENCES playlists(playlistid)
);
CREATE TABLE IF NOT EXISTS playlist_song (
playlistid INTEGER,
songid INTEGER,
songOrder INTEGER,
CONSTRAINT p_ps_fk FOREIGN KEY (playlistid) REFERENCES playlists(playlistid),
CONSTRAINT s_ps_fk FOREIGN KEY (songid) REFERENCES songs(songid)
);
Следующая попытка:
CREATE TYPE songs_type AS (
songid integer,
title character varying(25),
artists character varying(25),
album character varying(25),
year integer,
duration integer,
url character varying(25),
songOrder integer
);
CREATE OR REPLACE FUNCTION func() RETURNS songs_type AS
$$
DECLARE results_record songs_type;
BEGIN
IF EXISTS (SELECT 1 FROM auxium.users WHERE userid = '1') THEN
SELECT
s.songid,
s.title,
s.artists,
s.album,
s.year,
s.duration,
s.url,
ps.songOrder
INTO
results_record.songid,
results_record.title,
results_record.artists,
results_record.album,
results_record.year,
results_record.duration,
results_record.url,
results_record.songOrder
FROM
auxium.playlist_song ps
JOIN
auxium.songs s
ON
ps.songid = s.songid
JOIN
auxium.playlists p
ON
ps.playlistid = p.playlistid
WHERE
p.playlistid = (
SELECT
p.playlistid
FROM
auxium.user_playlist up
JOIN
auxium.playlists p
ON
up.playlistid = p.playlistid
JOIN
auxium.users u
ON
up.userid = u.userid
WHERE
u.userid = '1'
LIMIT 1
)
ORDER BY ps.songOrder;
ELSE
INSERT INTO auxium.users (userid, username) VALUES ('1', 'Haley')
ON CONFLICT DO NOTHING;
END IF;
return results_record;
END;
$$
LANGUAGE plpgsql;
1 ответ
Создайте тип, а затем верните его.
Я создал таблицу пользователей (идентификатор пользователя, имя пользователя), а затем создал тип с той же схемой, которую я выбираю. Вам нужно будет изменить его на столбцы, которые вы выбираете (при создании ТИПА).
Работает нормально.
CREATE TYPE users_type AS (userid integer,username character varying(10));
CREATE OR REPLACE FUNCTION fun() RETURNS users_type AS
$$
DECLARE result_record users_type;
BEGIN
IF EXISTS (SELECT 1 FROM users WHERE userid = 1) THEN
SELECT userid,username into result_record.userid,result_record.username from users;
ELSE
INSERT INTO users (userid, username) VALUES (1, 'Haley');
END IF;
return result_record;
END;
$$
LANGUAGE plpgsql;