How to make strings unique by certain parameters in postgreSQL? [duplicate] - postgresql

This question already has answers here:
Postgresql enforce unique two-way combination of columns
(2 answers)
Closed 20 hours ago.
Example: Let's say we have a friends table with columns user_id, friend_id, status. We need to be able to add:
user_id
friend_id
status
3
1
False
3
2
False
3
4
False
But it was impossible to add:
user_id
friend_id
status
1
3
False
2
3
False
4
3
False
In other words, so that IDs 1 and 2, 1 and 3 can be added and their reflections 2 and 1, 3 and 1 cannot be added.
Thank you in advance
I tried to make a composite key of user_id and friend_id consisting of foreign keys referencing to the same table. I also tried. I also tried to make these values unique, but in this case I can't add duplicates; for example 1 and 2, 1 and 3 (not added).

Unlike most many-to-many associations, this one is bidirectional. Both members are peers.
You can prevent a user from being friends with themselves with a check: check(user_id <> friend_id).
You can prevent duplicate friend relationships with a unique index on an expression that does not care about the order. For example, make an array and sort it.
create extension intarray;
create unique index on friends(
(sort(array[user_id, friend_id]))
)
User ID 3 / Friend ID 1 and User ID 1 / Friend ID 3 both result in [1, 3].
To get a complete list of a user's friends you need to search by both user_id and friend_id.
select count(*)
from friends
where user_id = $1 or friend_id = $1
This suggests it might be better to refer to them as friend1 and friend2 making the point that the relationship is bidirectional.
Demonstration.

Related

How to implement GraphQL Relay style cursor based pagination in postgres (with sqlalchemy and fastAPI)

I am trying to implement Relay-Style pagination on a postgres. I have gone through the relay specification, and it recommends having a globally unique cursor for each entity. The specification for pagination is that the client provides first and after for Forward pagination and last and before for Backward pagination.
Assume I have a table called Products, with an auto incrementing primary key integer ID. In the most basic case, pagination is very straight forward. For forward pagination it would be something like SELECT * FROM products WHERE id > cursor LIMIT 10 for forward pagination, and SELECT * FROM products WHERE id < cursor ORDER BY id DESC LIMIT 10
The problem arises when we have additional sorting requirements. Let us say, our product table has a name field on which we want to sort.
Name Id (cursor field)
Trendy 1
Autumn 2
Winter 3
Crazy 4
Antman 5
Marvel 6
And we want to paginate, with page size of 3, sorted on name ASC. The query would be:
SELECT * FROM products ORDER BY name ASC LIMIT 3, And we would get the following output:
(Antman, 5), (Autumn 1), (Crazy 4)
But now, how will I get the next three? This query SELECT * FROM products WHERE id >= 4 ORDER BY name ASC LIMIT 3; would not work, as Trendy has ID < 1. Do I create a different cursor for Name and use that for paginating with Name? Okay, what if we wanted to sort on multiple fields together (let us say we have a price field, we want to sort from decreasing to increasing price, and then sort based on created time, and then on name. The price might not be unique and any other additional constraints), how would I create a cursor then?
What is the standard approach to solve this problem? I have tried to research as much as I can but I couldn't find any information on how to accomplish this in fastapi and sqlalchemy. Django has FilterableConnectionField, but I couldn't understand the implementation. Any help is very appreciated, thank you.
edit: I figured out how to do this. It is called queryset pagination, and sqlakeyset repo on github had a good implementation of this pattern. https://github.com/djrobstep/sqlakeyset

How do I filter values from a many to many relationship?

If i have a many to many relationship between articles and tags, what is the best way to go about selecting all articles that contain tags that a specific user has stored?
For this example, assume there's a users table with a user_id column.
Articles
Article_id
Article_name
1
Dogs
2
Cats
3
Sheep
Tags
Tag_id
Pets
Outdoors
Grass
Article_Tags
Article_id
tag_id
1
Pets
1
Grass
1
Outdoors
2
Outdoors
3
Grass
3
Outdoors
Users_Tags
User_id
tag_id
User1
Pets
User1
Grass
User2
Pets
If I wanted to show all articles that has any of the tags that a user has stored associated with their id in Users_Tags, what would be the best way to do so? I mettled with nested selects and inner joins but I couldn't logic out the best way to go about this.
For example, since User1 has the tags Pets and Grass stored with their User_id, I would want to return the articles with the ID of 1 and 2, since both of those articles have at least one of the users' stored tags associated with it.
Article_id | Article_ Name |Tag_id
1 | Dogs | Pets
1 | Dogs | Grass
3 | Sheep | Grass
A sample output is provided above. I included repeats of the same article for clarities sake, although in reality I would like to only repeat an article a single time.
If I got it right, it should be ordinal structure with "inner join". Seemingly, the column "Tag_Id" contains a misprint since the table "Tags" don't have the "Cats" value.
Select A.Article_id, A.Article_name, U.Tag_id
From Users_Tags As U Inner Join Article_Tags As T On (U.Tag_id=T.Tag_id)
Inner Join Articles As A On (T.Article_id=A.Article_id)
Where U.User_id='User1'
If you want the articles that have common tags with a specific user, try this:
select * from articles A
where exists(select 1 from article_tags B
where B.article_id = A.article_id and B.tag_id IN
(select tag_id from users_tags where user_id = 'User1'));

Returning the best match from my database given a list of booleans

I hope this question is appropriate for this forum. I am setting up a PostgreSQL data base and need a few ideas on how to structure my tables so I can pull the data I need.
I know I need a table that contains information about different venues. There will be a column for the venue name and then several columns with details about the venue each containing a boolean. So for example column 1 will have the venue name, column two will be titled food and the data cell will either be true or false. There will be 15-20 columns.
I am going to get a list of user responses for each column (other than name) and want to return a list of venues ordered by best match.
Here is an example if I haven't been clear. I have a table with three entries:
Concert Hall, Yes, Yes, Yes
Opera, Yes, No, No
First Ave, Yes, Yes, No
I am receiving the user input which is (No, No, No)
My query should return:
Opera
First Ave
Concert Hall
It would be even better if I could get the % match as well: (66%, 33%, 0%)
You need the appropriate ORDER BY clause:
SELECT venue_name
FROM venue_table
ORDER BY cast(boolcol1 IS FALSE AS integer) +
cast(boolcol2 IS FALSE AS integer) +
cast(boolcol3 IS FALSE AS integer) DESC;
The expression in ORDER BY will be 3 if all three boolean columns are FALSE and 0 if they are all TRUE.

Postgres how can I make 2 numerical fields unique to each other

I am trying to do a following/follower type of concept that many social networks have. I have 2 INT fields called me and following, Those INT fields are composed of users Unique ID. I want to make so that if user 23 is following user 7 or 23->7 then user 23 can not follow user 7 again because the relationship already exists. This picture will clear things up
Notice above the first 2 rows are 31->27 or user 31 is following 27 twice that is redundant. Is there some constraint that I can use to prevent that from happening ? I am using postgres version 9.4
You can do this by creating a unique index. But not just any unique index, one on expressions:
create unique index unq_t_me_following
on (least(me, following), greatest(me, following));

recover sort order/position values using magmi with multiple website/store/storeviews

I've been using Magmi with great success, creating and updating our magento products on a daily basis.
Our production retail site generally uses the default/admin values for store. When I make new categories and populate them I generally use the category_reset=0 column to preserve the handmade sort order or position values for all of the original categories.
I've been working on a wholesale site set up with a seperate filesystem for all 3 levels of the Magento hierarchy. I did an import with magmi setting the store column to the wholesale site, with 2 additional collumns - sku and category_ids (without category_reset) using a sub-set of data exported from the admin store view (filtered the manufacturer column for only one manufacturer) to try to populate the wholesale site categories (same root catalog with certain categories disabled or not visible) with the same category products.
For some reason, I'm not sure why, (ouch, I realize now there was a typo in the header name for store) it did not update the right store - it defaulted back to admin and lost
the sort order for many categories, about 3k products imported ok.
I have 2 non-production sandbox sites with duplicate category data. I've been manually copying the category product listings with the desired position values into a new csv so I will have sku,category_id (singular),position_value
Many products are members of more than one category. My question is...
In order to regain the position values or sort order, what syntax should I use under category_ids? The products are already in the category so I would use a category_reset=0 column, right?
for an example record:
sku category_ids
45000 39,262,353
my next import might look like:
sku category_ids category_reset
abc 39::10 0
def 39::20 0
45000 39::30 0
ghi 262::10 0
45000 262::20 0
jkl 262::30 0
45000 353::10 0
mno 353::20 0
does this seem workable? I'm feeling very gunshy after having borked my production site with a typo and need some validation before I take steps to confuse myself further.
Thanks in advance for any insight.
As stated in the Magmi Documentation for Importing item positions in categories (from magmi version 0.7.18), the syntax is as follows:
sku,....,category_ids
000001,...,"8::1" < = put sku 00001 at position 1 in category with id 8
000002,...,"9::4,7" < = put sku 00002 at position 4 in category with id 9 and at position 0 in category with id 7
000003,...,"8::10" <= put sku 00002 at position 10 in category with id 8
So yes, your method should work. Be sure to do a full database backup before doing major import changes ;)