MySQL 3 column unique constraint not working, possibly due to NULL - mysql

This is my table, GameAdmin:
game_id company_id user_id
1 5 NULL
1 5 NULL
1 NULL 2
1 NULL 3
1 NULL 3
It links games to entities that can edit them (either a company or a user).
I have a UNIQUE index on all columns, but as you can see it's not working as expected.
What is wrong? Is it because of the NULLs?
I know I could make it work by changing the structure to:
game_id admin_type admin_id
1 company 5
1 company 5
1 user 2
1 user 3
1 user 3
But that's not compatible with my JPA/Hibernate setup, or at least very inconvenient, because it doesn't allow me to set the relations like this:
#ManyToOne(optional=true)
private User user;
#ManyToOne(optional=true)
private Company company;

Oh, the solution is so simple. I split the constraint up, so there's one for game_id and company_id, and for game_id and user_id.

It is because of the NULL value. They are not considered unique. If you don't have Foreign Keys on those fields, you might use 0 instead of NULL.

If you know (and I mean know, not guess) that you will never have more than 2 possible classes (user/company), just use negative IDs on one of them.
I know this is not 1NF
I know this is hacky
I know this is not really beautifull
But IMHO this is on the acceptable side of the "thin red line".

Related

How do I change the value of one field in SQL record to a value from another table?

First of all, I'm sorry if this is a bit of a dumb question. I checked what's written in similarly phrased questions like "How do I update fields from one table with values from another table" but the content doesn't seem to match what I'm trying to do.
Let's say I have a table called site_users:
user_id
login
password
user_id2
2
user
password
1
7
access
xyz
2
11
otherlogin
abc
3
15
somebody
defg
4
22
user
qwert
5
Then I have a lot of other tables in the same database, that have some columns of various names that are actually corespondent to the "user_id" of the "site_users" table. There are no relations set or anything like that. I want to change the values in the fields of those other tables to user_id2. So let's say I have a table: user_options:
admin_id
perms1
perms2
2
1
12139389
7
1
13232111
I want to change it to:
admin_id
perms1
perms2
1
1
12139389
2
1
13232111
How can I do that? This is the first time I'm doing anything other than just simple mass changes of text with some regex :/
If i am understanding your question correctly you should be able to do following where table1 is top table and table2 is table you are trying to update:
update table2 t set admin_id = (select user_id2 from table1 where user_id = t.admin_id)

How to ensure no gaps in auto_increment numbers?

i have a problem case with auto_incrementing, this is my table i have first it was so smooth to incrementing id*
id* name
1 name1
2 name2
3 name3
4 name4
5 name5
6 name6
but when I delete a record and insert a new record the id starts from 7.
id* name
1 name1
2 name2
3 name3
5 name5
6 name6
7 name7
this is what i want to make:
id* name
1 name1
2 name2
3 name3
4 name7
5 name5
6 name6
I would like a solution where every number is filled in, so if I delete a row the next autoinc number will be the number that I deleted not the next number higher.
First off, it's completely fine to have these gaps. There is no problem. It's just your OCD that forces you to think these numbers have to follow a pattern - they DON'T.
auto_increment is not a PHP feature, it's MySQL feature
auto_increment ensures every row gets a unique number. It doesn't deal with sequential numbers
auto_increment works safely in concurrent environment - that means there are a lot of users connecting to MySQL and doing stuff, and all of them have to be able to deal with the database and not get the same id for identifying a row. This is done through a rather complex process and this is one of the reasons why auto_increment yields gaps
auto_increment is used by InnoDB for physical organization of records on disk - it uses the feature of auto_increment and that one is producing a number that's larger than previous (that's what it does, larger than previous, not sequential). Using this, a b-tree is constructed and records are written in sequence on the hard drive. Tampering with auto_increment makes InnoDB rebalance the tree. It means it goes through records and recreates the index if you mess with it - that's something you don't want. Ever
When you think about it, what do you even get with sequential numbers? Nothing really, except your brain probably hurts less because there's some imaginary order.
For sequential numbers, use triggers to create them. auto_increment has one job and one job only - to produce unique numbers.
If you're trying to get something that looks like a list, I suggest you leave the field "ID" as is and add another field to use for names sorted numerically.
Anyway, you can get the same result with just a query like this:
SELECT name, #Rk := #Rk+1 AS Rank
FROM mynamestable, (Select #Rk := 0) AS Rk
Edit:
This query will return all records in the field name from the table mynamestable and also a column (named Rank) that will be a numeric incremental (starting from 1) so the result will be something like:
name Rank
Name1 1
Name2 2
Name3 3
for it you can use trigger after delete. Update all ids (decrease 1) which greater than deleted id
CREATE TRIGGER update_ids AFTER DELETE ON test_table
FOR EACH ROW SET UPDATE test_table SET id = id - 1 WHERE id > OLD.id;
also you must reset auto_increment or write another trigger for insert, which update id to max(id)

Link in three tables in php redbeans

I have three tables
USER
user_id,name
EVENT
event_id, name,desc
PARTICIPATION
id, type
1 yes
2 no
3 maybe
I want to handle relationship among these in table user_event_participation
id , user_id,event_id,participation_id
1 1 1 3
How can I do in redbeans
I am afraid that i don't get the problem fully.
But the way it seems to me is linking.
http://www.redbeanphp.com/link_beans
If you want full example please ask. ( I'm sorry, but I simply don't have much time right now)

Database design for chatroom application

EDIT
People think this question is too broad so I'm narrowing things down a bit here:
I have a table with dual primary keys: roomID and userID.
Here is some example data:
roomID | userID
1 | 5
1 | 9
1 | 10
1 | 12
2 | 5
2 | 9
2 | 10
3 | 5
3 | 17
Given a list of users: 5,9,10, how can I return the roomID containing ONLY those users? So in this case it should return 2.
I hope this can be done within 1 SQL query.
Any help would be appreicated.
ORIGINAL QUESTION
I am making a chat room application and need to design a database backend for it. All the rooms are created on the fly and are destroyed when the last user exits the room. Users are able to add other users to any room they are in.
Currently this is my design:
I have a chatroom table with two columns. The two columns are both primary keys for the table (so a row is considered duplicate only when both columns are the same). The first column is the room ID. The second column is a user ID. The idea I have here is with the same room ID, there can be many users in this room (so rows with same room ID but different user ID). When I need to create a new room, I simply select MAX(room ID) + 1 and create a new room with this ID and add the users into it.
Given a list of users IDs (such as 1,5,31,12), I need to find out if a room is already created for them. In other words, I need to determine if there are rows all with the same room ID having users IDs 1,5,31,12. However, if a room is created with users 1,5,31,12,6 (one or more extra users), this should not count as room already created. I will then need to create a new room for them and add the users to that. Same goes for less users than the list.
Right now I'm having trouble forming the query to determine if I need to create a new room or not, and if not, retrieve the room ID of the existing room.
Any help would be appreciated.
Also, I think this design is quite cumbersome, you are welcome to suggest a better database design.
P.S. the database I'm using is MySQL
I think yoy can add 1 more col to the chatroom table, name num_member, this is number of member in room( or better have room(room_id, number_member) table). To make it simple first, I assume you have num_member in chatroom. This query might work:
Select * From chatroom where user_id IN ($userIdList) Group by room_id HAVING count(*) = chatroom.num_member
Hope this help

Filtering SQL results

I would like to show a filtered result to a few ip's that keep scraping my content. I have blocked them with .htaccess and they change their ip address and continue doing it. So I thought, I want to create a soft block that won't show them all of my content and hopefully they won't even notice.
My table has a auto_increment field
id | category | everything else
1 1
2 1
3 4
4 2
I have been trying something like this.
SELECT * from mytable WHERE `category` = '1' having avg(id/3) = 1 ORDER BY `id` DESC LIMIT 0 , 10
I have searched forever but I am a newb to sql, so I don't even really know what I am searching for. I hope somebody here can please help me! Thanks :)
If you want to get remainder of division by 3, you should use % operator.
SELECT * from mytable WHERE `category` = '1' and id % 3 = 1 ORDER BY `id`
DESC LIMIT 0 , 10
Generally, the ID column is not for doing computations on it. It does not represent anything other than unique identifier of the record (at most, it should be used to sort the records chronologically) - you could have there GUIDs for example, and your application should work.
If you want to store the IPs that you want to block in your DB, consider adding another column to your table, call it status or something similar, and store in this column the status for that ip - this status could be clean, suspicious, blocked, etc. After that, your SELECT should look only after the rows with blocked status