SQL - Paging comments - sql

I have the Table Comment below:
CREATE TABLE Comment
(
CommentID int,
Username nvarchar(50),
Content nvarchar(255),
ReplyID int,
primary key (CommentID),
)
ALTER TABLE dbo.Comment
ADD FOREIGN KEY (CommentID) REFERENCES dbo.Comment (CommentID) ON DELETE NO ACTION ON UPDATE NO ACTION,
And I want to query paging comment in detail product with data:
+----+----------+-------------+---------+
| ID | Username | Content | ReplyID |
+----+----------+-------------+---------+
| 1 | UserA | hello | null |
| 2 | UserB | hello | null |
| 3 | UserC | Hi UserA | 1 |
| 4 | UserD | Hello World | null |
| 5 | UserE | Hi UserB | 2 |
+----+----------+-------------+---------+
How can I show comments with paging, and displayPerPage = 2, example:
UserA: Hello
UserC: Hi UserA
UserB: Hello
UserE: Hi UserB
>>More Comments<<
Any help will be appreciated.
Solution 1: using Outer Join

You could use a query similar to the following to get the Comments in the correct order:
select case when c.ReplyId is not null then ' ' else '' end
+ UserName + ': ' + c.content Line
from Comment c
order by IsNull(c.ReplyId, c.CommentId), c.commentId

Related

Check if value of referenced row matches value in current row

See the following database structure:
v---------------------------------------------------|
v----------------------------|---------------------------| |
+---------------+ +----+---------+------+ +----+---------+---------+-----+
| id | username | | id | user_id | tag | | id | user_id | message | tag |
+----+----------+ +----+---------+------+ +----+---------+---------+-----+
| 1 | User1 | | 1 | 1 | tech | | 1 | 1 | Test1 | 1 |
| 2 | User2 | | 2 | 1 | news | | 2 | 2 | Test2 | 1 |
+----+----------+ +----+---------+------+ +----+---------+---------+-----+
users tags messages
tags.user_id and messages.user_id both reference users.id. messages.tag references tags.id.
Users have tags available (rows in tags where rows.user_id = users.id) and messages (rows in messages where messages.user_id = users.id).
The problem is that any tag can be "attached" to the message, instead of only tags that are owned by the user. So I need an extra restriction that ensures that the tag referenced in messages.tag not only exists (foreign key restriction), but is also owned by the same user as the message itself (messages.user_id = tags.user_id).
I have not found a way yet to achieve this restriction, which is why I'm asking help.
python: 3.8.10
sqlite3.version: 2.6.0
sqlite3.sqlite_version: 3.31.1
From the manual creating a composite FK in Sqlite3 looks like:
CREATE TABLE parent(a PRIMARY KEY, c, d, e, f);
CREATE UNIQUE INDEX i1 ON parent(c, d);
CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d));

How to join two table to update one in Postgresql

I have two table user_table and subscription_table
user_table
| user_id(int)| email(varchar) | phone(int)|
------------------------------------------------
| 1 | abc#gmail.com | 9910256256 |
| 2 | def#gmail.com | 8856956325 |
| 3 | ghi#gmail.com | 8745692455 |
| 4 | jkl#gmail.com | 7852369526 |
subscription_table
| email(varchar) | type(varchar)| is_subscribed(boolean)
------------------------------------------------------------------
| abc#gmail.com | news | true
| abc#gmail.com | video | false
| def#gmail.com | news | true
| def#gmail.com | video | true
I have user_id and want to update is_subscription. Best wayto update is_subscription.
I have tried to do it with multiple query but i think that is not good.
Is this what you want?
update subscription_table s
set is_subscription = ?
from user_table u
where u.email = s.email and u.user_id= ?;
Note: If you have a user_id, then you should be using that for foreign key relationships. I don't understand why email would be used for this purpose.

Reducing a Postgres table to JSON

I have a following table in Postgres
+----+-----------+----------------------+---------+
| id | user_fk| language_fk | details |
+----+-----------+----------------------+---------+
| 1 | 2 | en-us | 123 |
| 2 | 3 | en-us | 456 |
| 3 | 4 | en-us | 789 |
| 4 | 4 | es-la | 012 |
+----+-----------+----------------------+---------+
And I want to reduce this to the following SQL statement:
UPDATE users SET details = '{"en-us": "789", "es-la": "012"}' WHERE id = 4;
UPDATE users SET details = '{"en-us": "123"}' WHERE id = 2;
UPDATE users SET details = '{"en-us": "456"}' WHERE id = 3;
So I want to reduce languages per user and put it in a different table. Is there a way to do this in Postgres?
Use the function jsonb_object_agg() to get the expected output:
select
min(id) as id,
user_fk,
jsonb_object_agg(language_fk, details) as details
from users
group by user_fk
id | user_fk | details
----+---------+----------------------------------
1 | 2 | {"en-us": "123"}
2 | 3 | {"en-us": "456"}
3 | 4 | {"en-us": "789", "es-la": "012"}
(3 rows)
You cannot update the table in this way because of different types of old and new details column. Create a new table with reduced columns using create table from select:
create table new_users as
select
min(id) as id,
user_fk,
jsonb_object_agg(language_fk, details) as details
from users
group by user_fk;

A good SQL Structure for grouped comments with replies

I have two tables: News, Images. Both could have comments, so i decided try to make a generic comments table. Also comments could have a reply. I solved two possible methods, but i dont know which choose in order of a good practice or good performance solution.
Method 1 (which i am using):
News:
| ID | CommentGroup | Content | ...etc
Images:
| ID | CommentGroup | Url | ...etc
Considering the next image:
| 14 | 22 | http://image.gif | ...etc
Where the comments could be these:
|UserA:
| Coment1
|
|--|UserB -> UserA:
| Coment2
|
|---|UserC -> UserB:
| | Comment4
|
|UserD -> UserA:
| Coment3
Resulting Comments:
| ID | Group | ReplyGroup | Replied | Content | User |
| 13 | 22 | NULL | 1 | Comment1 | UserA |
| 17 | 22 | 13 | 1 | Comment2 | UserB |
| 11 | 22 | 13 | NULL | Comment3 | UserD |
| 15 | 22 | 17 | NULL | Comment4 | UserC |
If after commented Image14, is created a New, i decide the future comments group number by counting the max of the group column (22) so add 1 (23).
New:
| ID | CommentGroup | Content | ...etc
| 14 | 23 | A new | ...etc
Comments:
| ID | Group | ReplyGroup | Replied | Content | User |
| 22 | 23 | NULL | 1 | Comment1 | UserA |
| 30 | 23 | 22 | NULL | Comment2 | UserB |
Method 2
taken from this question:
News:
| ID | Content | ...etc
Images:
| ID | Url | ...etc
Comments:
| ID | Group | Type | ReplyGroup | Replied | Content | User |
Where type dintincts between News or Images Group.
how you think is better?
or what other solutions are possible?
Thanks.
Initially as a basic implementation I would treat everything as 'content' grouping common attributes.
CONTENT (
id int primary key,
created_on datetime,
created_by int
)
Then have more specific tables of the types of content
e.g.
NEWS (
content_id int primary key foreign key references content(id),
article nvarchar(max)
)
and
IMAGES (
content_id int primary key foreign key references content(id),
url varchar(1000)
)
and
COMMENTS (
content_id int primary key foreign key references content(id),
parent_id int foreign key references content(id)
root_id int foreign key references content(id),
level int,
text nvarchar(2000)
)
Each of these would have a 1:1 relationship with CONTENT.
COMMENTS would then reference other content 'directly' via the parent_id, the reference being either an image, news or indeed another comment.
The root_id in the COMMENTS would reference the actual image or news content (as would the parent_id of all 'top level' comments). This adds the overhead of maintaining the root_id (which shouldn't be too difficult) but will aid selecting comments for some content.
e.g.
-- get the article
SELECT *
FROM content
JOIN news
ON news.content_id = content.id
JOIN users
ON users.id = content.created_by
WHERE content.id = #news_id
-- get the comments
SELECT *
FROM content
JOIN comments
ON comments.content_id = content.id
JOIN users
ON users.id = content.created_by
WHERE comments.root_id = #news_id

Insert into row if value exists in a different table

I have two tables:
Users:
+---------------------+---------------------+
| UserId | ValueToUpdate |
+---------------------+---------------------+
| 1 | |
| 2 | |
| 3 | |
+---------------------+---------------------+
Subscribers:
+---------------------+
| UserId |
+---------------------+
| 1 |
| 2 |
+---------------------+
I need to write a SQL query that will insert some value into the Users table, column (ValueToUpdate) if the user id in the Users table exists in the Subscribers table.
Essentially I'm looking for something like this
UPDATE Users
SET ValueToUpdate = "some value"
WHERE (UserId from the Users table exists in the Subscribers table);
How could I achieve this?
You can do this using an exists clause:
UPDATE Users u
SET ValueToUpdate = 'some value'
WHERE EXISTS (SELECT 1 FROM Subscribers S WHERE s.userid = u.userid);