Ensure single vote per user, per page, in a database - java

I'm working on a small feature in a Java web application that very closely resembles the vote up/down feature here at stackoverflow.com. I have a database that looks like the following:
VOTE TABLE
id (bigint): surrogate primary key
question_id (bigint):: the question the vote is for
vote_type (int): whether the vote is up or down
user_id (varchar): the username of the person who the vote belongs to
I want to ensure that there is only one vote in the DB per person, per question. What is the best way to enforce this? How would enforce it with the database schema I have described above?
I am currently having problems where a user fires off two vote-up requests and the database then contains 2 'up votes' for that user, when they should only have one vote.

You can enforce is via a Primary Key or Unique index - both concepts are pretty univeresal within databases. Place it on the two columns together, Question_id and User_id. That would only permit 1 entry per user, per question. This will be enforced by the database, even if your application codes lets them vote twice, the database will throw an error on the second record attempting to be inserted. (Even if you are using transactions etc, the database will enforce it correctly.)

If you want to enforce it via database schema, the correct way would be to make (question_id, user_id) an unique key.

Only do the INSERT when user_id and question_id NOT EXISTS e.g.
INSERT INTO TABLE
-- ALL YOUR FIELDS HERE
WHERE NOT EXISTS (
SELECT * FROM TABLE WHERE
QUESTION_ID = ? AND USER_ID = ?
)
However you could make user_id and question_id the Primary Key (or another Unique key) so only one record is physically allowed.

Related

Increment ID on insertion of a new row on database

I need something which I dont know if it's possible to achieve. Basically I'll be adding new rows of information from java to a database with the table structure , ex:
Number | Color | Size
0 | Red | Big
1 | Green | Small
2 | Yellow| Medium
I'm using java and I'll only input the Color and Size, and I would like to know if it's possible to create a trigger that will store the variable Number(id) on the database side, and increment it each time I do an Insert of a new row into the db. I was thinking doing something like, " INSERT INTO table ((null),'Red', 'Big'), and then the database would update the value with the proper Number.
Also should be possible to bare with fact that some rows can be deleted, but it won'shouldn't affect anything, example: if I have ID's 0 , 1 ,2 and I delete 1, next row should still be 3.
Another thing, I'm using Sybase SQL Anywhere 12 to do this.
You should use autoincrement column in your database.
See this.
http://www.sqlines.com/sybase-asa/autoincrement_identity
As #Gordon Linoff said ...
Identity columns are doing that, for example ...
create table T1 (ID int identity(1,1), Name nvarchar(100))
In this case you would go ...
insert into T1 (Name) values ('John')
So, you would insert Name 'John' and DB itself would give him ID 1
Next time you do insert, ID 2 would be set ... and so on and on ..
Identity(1,1) - it means start from 1 and increment it by 1 on new insert
Thing about this is that once number is taken, there is no going back, so if you have IDs 1, 2, 3 .. and delete ID 3 .. on next insert ID will go up to 4, it will not populate "missing number"
there are several solutions that satisfy your requirements but those are different in several aspects and you should decide to select the best one.
some solutions are exists in DB context. (for example #Gregory answer),
but some other solutions are independent of the DB type and specific features. it means that you implement your solution independent of your db type and you could change your db (oracle, sql-server, my-sql , ...) and there is no need to change your java code.
in jpa there are three Sequence Strategies to solving this problem with #GeneratedValue.
1) Table sequencing: you use a separate table for this purpose in your db. this table hold the proper ids for other tables that have auto-increment-columns with this strategy.
2) Sequence objects: you use a sequence object in your db and jpa handle it. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres.
3) Identity sequencing: uses special IDENTITY columns in the database to allow the database to automatically assign an id to the object when its row is inserted. Identity columns are supported in many databases, such as MySQL, DB2, SQL Server, Sybase, and PostgreSQL. Oracle does not support IDENTITY columns but it is possible to simulate them using sequence objects and triggers.
if you want to be independent from your db type, I recommend you to use "table strategy" in jpa.
see Java Persistence/Identity and Sequencing for details.
you asked:
I would like to know if it's possible to create a trigger that will
store the variable Number(id) on the database side, and increment it
each time I do an Insert of a new row into the db.
yes, you could use trigger, but as i mentioned there are some simpler solutions rather it.
Also should be possible to bare with fact that some rows can be
deleted, but it won'shouldn't affect anything
in jpa solutions the deleted ids don't be used in next usage, but if you implement your own solution you could use them.
I hope this answer help you.

MySQL Insert User and Password at the same time, but in different tables

So I have a MySQL database schema where there is a USERS table which contains the ID as a primary key for that table, I also have a USER_PASSWORDS table which references the USERS table where the USER_ID will act as a foreign key in this table.
The issue that I am facing is that I am writing an application where the user will be able to sign up and specify a username and password. But I would like to insert the user into the database with one query.
I was thinking I had to insert the username first into the USERS table and see what ID has been given to that username and then insert the hash of the password that the user has entered into the USER_PASSWORDS table and specifying the ID that was queried.
I dont like this approach because it means that I have to:
INSERT into the database
QUERY the database
INSERT into the database again
Is there a better way of doing this?
Thanks
You can't insert into two tables with one insert statement, and you would have to query the users table anyway to get the ID value to insert as a foreign key for the user_passwords table.
Really the only way to do what you want is the solution you've already identified:
Insert into the Users table
Query to get the ID of the User you just inserted
Insert into the USER_PASSWORDS table with the ID you obtained for the User.
You could wrap all this up in a stored procedure that takes user data and password as parameters, which would be the "better" way of doing it.
As you didnt really tell for what system / programming language you need this and you did not provide any code example either, I can only give you some theory what you could do:
Its impossible to insert data into two different MySQL tables with one queries but you can reduce your script atleast by the SELECT query:
1.) There is a function in most mysql apis (Depending on what programming language and MySQL Library you are using) that says "getLastInsertId()", "lastInsertId()" or similar.
This will return the ID that was inserted by the auto-increment of the table after the insert is completed.
Just check the docs of your MySQL-api it will have such a function.
2.)
The second possibility is using a UUID - a very large (commonly 128-bit) long string which is generated totally random. There are more so many possible combinations it will happen more probably that you win in the lottery 10 times in a row then you generate two times the same UUID that is already in your table.
So you just generate the UUID and insert it as a key in both tables and you are done.
Just use google to find out-of-the-box libraries to generate UUID's you dont need to build the alogrithm on your own.
An UUID could looks like this:
4a34fe87-f577-4ea9-9557-1bc8f779a68c
One solution: since the hash is unique you can use the hash as a primary key in the USERS table. Then you know what the primary key (id) is at the time of the insert and can reuse when INSERTING in the USER_PASSWORDS table.
That way you can avoid the id query at least.

Special record in Database table, if changed, it should reflect changes in all other records associated

I have some four database tables One table has two fields of interest which are set by the user at first download - first run.
The user sets his name and date of birth - after processing I assign this name and DOB to various records in other tables(In other tables there are only two possibilities either the record is associated with the owner who sets the name and DOB or user can associate a record with his friend using his friends name and DOB). Now I want to give the use a functionality to edit this record which is his name and DOB. However editing this one record should also trigger a change in all other records in other tables which are associated. Is there something inbuilt in SQLite to make this happen or do I have to loop through all records in all tables and change them manually?
Why don't you normalize your tables?
You could do:
table USER:
UserId(key), name, dateOfBirth
table OTHER:
fieldA, fieldB, fieldC, UserId (foreignKey)
That way you don't have to update the other tables accordingly. Depending on your usage scenario this might be the better way to go (e.g. in a traditional transactional setting). If you are in data-warehousing,... it might be better to denormalize your tables
If you have the user's name and DOB set as a foreign key to those other tables, you can also set a cascading trigger in the foreign key. When you create the table with that foreign key, you can set the ON UPDATE attribute to cascade, which will mirror that change in the user's information across any other entries that have it set as the foreign key.
https://www.sqlite.org/foreignkeys.html has more information on the topic.
The normal way is to introduce a (hidden to user) primary key, an autoincrement counter, and use that to access the record. UserID or such. Other tables then relate to the user via a UserID.
SQLite uses ROWID aka INTEGER PRIMARY KEY (specific to SQLite).

Many subscribers for many shops

I have many shops in Shop table and many users in User table in DB.
User can subscribe to any stores.
How can I create table for this task? First column with shop name and second column - string with comma separated user ids?
This is generally referred to as a many-to-many relationship. In a standard relational database, this is usually represented by a table with user_id and shop_id, one row for each user -> shop relationship.
You will never want to use a comma-separated string to represent multiple items in a database, as this will make queries very inefficient. For example, to find which stores user a subscribes to, you would have to parse each row of the table to find which of the comma-separated values contains a.
This is a many-to-many relationship. You need a third table, say it's called Subscription. The fields will be two foreign keys, one referencing the primary key of the User table and the other referencing the primary key of the Shop table.
You can create a table where each row represents a subscription (i.e., a pair (user,shop)).
So, you will have (at least) two columns in the table: the id of the shop and the id of the user.
Assuming that a user can subscribe to a shop only once, the pair (user_id,shop_id) should be the primary key of the table (in case you need to define a surrogate key for the table, you could add a unique constraint to the pair (user_id,shop_id)).
If you have many data and need to quickly get all the shops to which a user has subscribed, you should add an index to the user_id column.
On the other hand, if you need to quickly get all the user that subscribed to a shop, you should add an index to the shop_id column.
I believe user can subscribe to multiple shops, and one shop can have multiple users subscribed to it. In this case, it is best to use map table with shop_id from shop table and user_id from user table. ( keep the foreign key constraints) . For each subscription ,this table will keep an entry, hence no comma separated string is necessary.
It sounds like you have a classic situation in databases which marks the change between a "flat file" database and "relational database" like MySQL, Oracle or MS's SQL Server. A similar situation is Authors and Books. An author can have more than one book and some books have more than one Author.
A simple comma delimited database is a flat file and you are going to need a separate line for each relationship. For example,
ShopA, UserA
ShopB, UserA
ShopA, UserB
ShopB, UserB
In a relational database, you can isolate the user table and shop table in two separate tables and form a third table, a relations table that describes the relation and so remove redundancy in the user and shop tables,
ShopTable
ShopA, SA
ShopB, SB
UserTable
UserA, UA
UserB, UB
ShopUserRelationTable
SA, UA
SA, UB
SB, UA
SB, UB
When you want records displaying the relationship, you apply the SQL language to create a sequence of records displaying this.
This basic problem of removing redundancy in tables is what motivates the development of relational database software.
It sometimes happens that a table is complicated enough to contain "many to many" relationship like this and SQL can be further applied to analyzing and creating records reflecting these relationships. Such a table may also serve as a many to many relationship table for other tables.

one to many mapping

I have a problem of mapping some scenario into data base.Problem is something like this.
There are two entities called Employee(empID,empName) and Task(taskID,taskName).
A employee can have ZERO-OR-MORE tasks.
A task can have ZERO-OR-ONE employee.
What will be the table structure that should I follow..
I'm going to implement this scenario using spring MVC and hibernate in java.How can I fixed this issue..
Any idea?
Thanks in advance!
Looks like you may need another table called EMPLOYEE_TASKS:
ID - sequence, PK.
EMPLOYEE_ID, numeric, not null, FK to ID in the EMPLOYEE table.
TASK_ID - numeric, unique key, not null, FK to ID in the TASKS table.
Your 0-or-1 employees/task requirement is handled by the UK on TASK.TASK_ID.
Your 0-to-many tasks per employee is handled by the EMPLOYEE_ID+TASK_ID pair. Because TASK_ID is unique, this pair doesn't need to be. In the real world, I'd probably make this an index.
Now I'd use hibernate's reverse engineering tools to create annotated models. We put the primary key sequence generator specifications in the reveng.xml file.
If every task had exactly one employee, this table would not have been needed. We could add an EMPLOYEE_ID to the TASK table but two tasks would likely have no EMPLOYEE. This means we couldn't make that column a UK. So we'd have a hard time using the database to enforce the zero-or-one constraint.

Categories

Resources