making the auto increment IDs start by a predefined number - sqlalchemy

I was asked to make the ids of our equipement start with the current year (eg : 21-4234 instead of just 4234) and I was wondering if this was possible. This is how we make the ids for our equipement:
id = db.Column(db.Integer, primary_key=True)
if anyone knows how this can be achieved i would love to hear from you :-)

Related

Database design for upvote/downvote in discussion forum?

I have a webite where there is a discussion forum. All questions have unique ID and answers have also unique ID with a foreign key referencing to question ID.
I have a user logged in. Using ajax, I can send the data(upvote/downvote,QID/AID, username).But there are few problems.
Whenever user logs back in, I want that when he opens a question, his previous upvotes and downvotes should be displayed.
A user cannot upvote/downvote a same question multiple times. Like if he upvoted a question to +1, he can only downvote it, not upvote it again.
Solution according to me. I am thinking of maintaining a table where username is the primary key and another attribute is a list of all the upvotes and downvotes he has done. Example:
(username, array)
(baqir, up_A001 up_A050 down_Q011 up_Q123)
Whenever the user logs in, I take this array and make sure all the previous upvotes and downvotes of the user are as it is. If there is a new vote,I add it to the array.
Is there any better solution?
P.S. Not necceassary but my current database structure.
class Question(models.Model):
QID = models.CharField( default="",max_length=1000, primary_key=True)
title = models.CharField(max_length=30, default="")
description = models.CharField(max_length=1055, default="")
date = models.DateTimeField(default=datetime.now, blank=True)
username = models.CharField(max_length=6, default="")
votes = models.IntegerField(default=0)
approved = models.BooleanField(default=False)
def __str__(self):
return self.title
class Answer(models.Model):
AID = models.CharField(max_length=1000, default="", primary_key=True)
QID = models.ForeignKey(Question,on_delete=None)
description = models.CharField(max_length=1055, default="")
date = models.DateTimeField(default=datetime.now, blank=True)
username = models.CharField(max_length=6, default="")
votes = models.IntegerField(default=0)
approved = models.BooleanField(default=False)
def __str__(self):
return self.AID
I am using Django. And I basically want whatever stackoverflow has implemented for their voting of questions and answers.
What array people, what are you talking about? You make another table per Q/A or per user, or a table where you just link two things, i.e. user and Q/A and its votes where keys can be repeated (no primary keys for this table).
Any array-like thing is loss of time and energy and it is against good DB design rules anyway.
Example of table keeping votes:
Table votes:
UID | QID | AID | VOTE
So you connect each user with each question or answer he/she voted. QID or AID can be NULL. When you come to some question, you just check whether table votes has anything to say about it and answers tied to it. If current QID and UID match and you get result, you just act accordingly.
This has a potential of being slow if you have a lot of users, but essentially will work nice.
Second solution is to tie your question/answer with another table keeping in only users that did something (up/down voted it). This will make DB look messier but when your user comes to given Q and its answers you just check whether this table has something to say aboutsaid visitor or not. If I am not clear enough I repeat, new table per each Q and/or A.
You can apply same technique in reverse, i.e. connect user to a table that holds all Q/A that the user voted, which will perhaps be the best way of keeping order and efficiency. So each time the user comes to any Q page you check if he/she have any history for that Q.
No arrays, no nonsense. Just one extra request to check status for currently viewed Q/A.
CREATE TABLE QuestionVotes (
UID ..., -- User id
QID ..., -- Question id
vote ENUM('up', 'down'),
PRIMARY KEY(QID, UID) -- for finding voting status of a question
INDEX(UID, QID) -- if you need the votes by a user
) ENGINE=InnoDB; -- to get benefit of clustered PK
Ditto for AnswerVotes.
Upvote/downvote: See if the row exists, if not, create the row. If row exists, either delete the row or complain that the user is up/downvoting twice.
Do not use arrays. It will become too painful.
If Django won't let you have composite PRIMARY KEYs, abandon Django.
Do not have 1000-char keys in the table. Disk space and performance will suffer.
User can be only 6 characters. Not optimistic about scaling big?
Upvote and Downvote scenario can be handled using code,If the last vote is a upvote user have permission only to downvote, if the user downvote he has permission to upvote, but for keeping status as you told you can keep a history in a array.
the first approach suggested by Dalen seems best
make a separate table for storing votes, and before performing any up/downvote action, check if the user has done any similar action before.
In case he has done opposite action before, delete/deactivate his previous entry in table and make a new entry.
And in case he has already performed the same action for the question before, do nothing, as his up/downvote has already been accounted.
Making a table for such tasks is highly encouraged, as it will not only make your task easier, it will give you a lot more flexibility, like you can add a timestamp with each action to track history or you can hit a count query on the table to find the total actions performed on a question

SQL database (Django) - Relate all records in table B to each record in table A

I'm working in Django, but this question could apply to any database in general.
In my models, I have a UserProfile table. Another table UserQA contains a field for question_text and a field for question_answer. The problem with this model is that I would need a ManyToMany relation that has the overhead of two longints per question, and the question_text is duplicated for each user.
Basically, the requirements are:
Table of questions which users can contribute to by adding their own questions
Store 1 character answer (Y/N/O/Null) to each question for every user
2.1 Is there a way to extend this if I want some questions to have more complex answers?
This seemed like an easy problem, but I can't figure it out... The way I thought of doing it seems very inefficient, is there a better way?
Thanks!
You will need another model, can be Question. The final result would be something like:
class User(models.Model):
user_name = models.CharField(...)
class Question(models.Model):
question_text = models.CharField(...)
class UserAnswer(models.Model):
question = models.ForeignKey(Question)
user = models.ForeignKey(User)
answer = models.CharField(...)
If you want more complicated answers, like especific values, lists of values, you can create one more model:
class QuestionAlternative(models.Model):
question = models.ForeignKey(Question)
value = models.CharField(...)
And then redefine UserAnswer:
class UserAnswer(models.Model):
question = models.ForeignKey(Question)
user = models.ForeignKey(User)
answer = models.ForeignKey(QuestionAlternative)
With this, you will have the Questions in one place, one UserAnswer per question, and the QuestionAlternatives how many times they must exist. Does not worry about the ForeignKey fields, they are not overheads and they build beautiful, reusable structures.

MySQL: Storing a list in separate columns? Or is there something better?

So, I'm moderately experienced in PHP/MySQL, I've done a few things before like creating a small chat website or even a small page analytics app. This most recent project, though, is challenging my abilities.
So, I'm designing this app for a school. I have a list of users and a list of classes. I would like to be able to assign a user to multiple classes (Right now I'm storing a single assignment by referencing a UID for the entry in the classes table). Would I have to achieve this by putting in additional columns for each possible assigned class (Having a column for their first class, second class, and so forth to some limit)? Would I have to limit my users to a number of assigned classes? Or is there a more elegant solution? I know that it's recommended to not do a comma separated list in the single cell either (And I can agree on that, as I plan to search for students based on the class UID and such).
So, sorry that I am a bit new to this, but I'm really not sure how to do this. The column for each assigned class would work, but I feel like there should be a more elegant solution.
Anyway, please do let me know, thank you.
Use a third table to handle the many-many relationships. The class_roll table contains two fields, class_id & student_id. Both are primary to avoid duplicates. This was a class can have zero or many students and a student can be assigned zero or many classes
class
-----
+ class_id
class_name
...
student
-------
+ student_id
student_name
...
class_roll
----------
+ class_id
+ student_id
In short you need a third table to track relationship between users and classes
user 1 - class 1
user 1 - class 2
...
user 2 - class 2
...
Make the 2 fields as PK to be sure user 1 cannot be twice enrolled in class 1 for instance.
You will need to make sure deletions in the users and/or classes tables are somehow propagated here and you will be in the right track

MySQL 5.5 Database design. Problem with friendly URLs approach

I have a maybe stupid question but I need to ask it :-)
My Friendly URL (furl) database design approach is fairly summarized in the following diagram (InnoDB at MySQL 5.5 used)
Each item will generate as many furls as languages available on the website. The furl_redirect table represents the controller path for each item. I show you an example:
item.id = 1000
item.title = 'Example title'
furl_redirect = 'item/1000'
furl.url = 'en/example-title-1000'
furl.url = 'es/example-title-1000'
furl.url = 'it/example-title-1000'
When you insert a new item, its furl_redirect and furls must be also inserted. The problem appears becouse of the (necessary) unique constraint in the furl table. As you see above, in order to get unique urls, I use the title of the item (it is not necessarily unique) + the id to create the unique url. That means the order of inserting rows should be as follow:
1. Insert item -- (and get the id of the new item inserted) ERROR!! furl_redirect_id must not be null!!
2. Insert furl_redirect -- (need the item id to create de path)
3. Insert furl -- (need the item id to create de url)
I would like an elegant solution to this problem, but I can not get it!
Is there a way of getting the next AutoIncrement value on an InnoDB Table?, and is it recommended to use it?
Can you think of another way to ensure the uniqueness of the friendly urls that is independent of the items' id? Am I missing something crucial?
Any solution is welcome!
Thanks!
You can get an auto-increment in InnoDB, see here. Whether you should use it or not depends on what kind of throughput you need and can achieve. Any auto-increment/identity type column, when used as a primary key, can create a "hot spot" which can limit performance.
Another option would be to use an alphanumeric ID, like bit.ly or other URL shorteners. The advantage of these is that you can have short IDs that use base 36 (a-z+0-9) instead of base 10. Why is this important? Because you can use a random number generator to pick a number out of a fairly big domain - 6 characters gets you 2 billion combinations. You convert the number to base 36, and then check to see if you already have this number assigned. If not, you have your new ID and off you go, otherwise generate a new random number. This helps to avoid hotspots if that turns out to be necessary for your system. Auto-increment is easier and I'd try that first to see if it works under the loads that you're anticipating.
You could also use the base 36 ID and the auto-increment together so that your friendly URLs are shorter, which is often the point.
You might consider another ways to deal with your project.
At first, you are using "en/" "de/" etc, for changing language. May I ask how does it work in script? If you have different folders for different languages your script and users must suffer a lot. Try to use gettext or any other localisation method (depends on size of your project).
About the friendly url's. My favorite method is to have only one extra column in item's table. For example:
Table picture
id, path, title, alias, created
Values:
1, uploads/pics/mypicture.jpg, Great holidays, great-holidays, 2011-11-11 11:11:11
2, uploads/pics/anotherpic.jpg, Great holidays, great-holidays-1, 2011-12-12 12:12:12
Now in the script, while inserting the item, create alias from title, check if the alias exists already and if does, you can add id, random number, or count (depending on how many same titles u have already).
After you store the alais like this its very simple. User try to access
http://www.mywebsite.com/picture/great-holidays
So in your script you just see that user want to see picture, and picture with alias great-holidays. Find it in DB and show it.

Calculating and DB Design for getting an average

I'm trying to wrap my head around the proper design to calculate an average for multiple items, in my case beers. Users of the website can review various beers and all beers are given a rating (avg of all reviews for that beer) based on those reviews. Each beer review has 5 criteria that it's rated on, and those criteria are weighted and then calculated into an overall rating for that particular review (by that user).
Here are some of the relevant models as they currently stand. My current thinking is that all beer reviews will be in their own table like you see below.
class Beer(models.Model):
name = models.CharField(max_length=200)
brewer = models.ForeignKey(Brewery)
style = models.ForeignKey(Style)
.....
class Beerrating(models.Model):
thebeer = models.ForeignKey(Beer)
theuser = models.ForeignKey(User)
beerstyle = models.ForeignKey(Style)
criteria1 = models.IntegerField
...
criteria5 = models.IntegerField
overallrating = models.DecimalField
My real question is how do I calculate the overall beer average based on all the reviews for that beer? Do I keep a running tally in the Beer model (e.g. # reviews and total points; which gets updated after every review) or do I just calculate the avg on the fly? Is my current db design way off the mark?
I'll also be calculating a top beer list (100 highest rated beers), so that's another calculation I'll be doing with the ratings.
Any help is much appreciated. This is my first web app so please forgive my noob-ness. I haven't chosen a DB yet, so if MYSQL or PostgresSQL is better in some way over the other, please provide your preference and perhaps why if you have time. I'll be choosing between those two DB's. I'm also using Django. Thank You.
As long as you're using Django version 1.1, you can use the new aggregation features to calculate the average whenever you need it.
Something like:
from django.db.models import Avg
beers_with_ratings = Beer.objects.all().annotate(avg_rating=Avg('beer__overallrating'))
Now each Beer object will have an avg_rating property which is the average of the overallrating fields for each of its associated Ratings.
Then to get the top 100:
beers_with_ratings.order_by('avg_rating')[:100]
As regards database choice, either is perfectly fine for this sort of thing. Aggregation is a basic feature of relational databases, and both Postgres and Mysql can do it with no problem.
You might want to have a look at Django ratings module. It's very nicely structured and provides a powerful ratings system. And not overly complicated at the same time (although if this is your first web-app it might look slightly intimidating).
You won't have to deal with calculating averages etc. directly.
Edit: To be a bit more helpful
If you use django-ratings, your models.py would probably look something like this:
class Beer(models.Model):
name = models.CharField(max_length=200)
brewer = models.ForeignKey(Brewery)
style = models.ForeignKey(Style)
.....
criteria1 = RatingField(range=5) # possible rating values, 1-5
...
criteria5 = RatingField(range=5)
No need for Beerrating model. Instead all the ratings information will be stored in Vote + Score models of django-ratings.