Database design for an auction style website - php

I'm creating an auction style website where users can bid for items. I've into a bit of confusion regarding the database design when it comes down to projects and bidding features. Initially I thought a table called 'project' could contain a multiple-valued column called 'bids' containing bid_id's.. However after a bit of research it appears this method is a no-no.. But I'm sure I can remember a lecture or two from university that mentioned multi-valued columns in database designs. What would be the best approach for the problem?
Thanks
Dan

It depends on your requirements on how to design the database. If you have exactly one auction per product ID, a BID table may be enough. If each auction requires individual configurations you may end up with an AUCTION table as well:
The product table
PRODUCT
PRODUCT_ID -- primary key
....
Auction table
AUCTION
AUCTION_ID -- PK
PRODUCT_ID -- foreign key to PRODUCT
START_TIME
END_TIME
MODE -- e.g. dutch, english...
...
Bid table
BID
BID_ID -- PK
AUCTION_ID -- foreign key to AUCTION
AMOUNT
TIME
...
In general, you should avoid multi-valued columns in a relational database model. You should aim for normalization. If it later comes to query optimization you may need to introduce further indexes, views and/or procedures.

In my opinion, the best solution would be to have a table bids containing all the necessary information in columns, for example: bid_id, product_id, bid_amount, bid_time, etc.

this is only meta-sql, you know.
users: id, ...
bids: id, auction_id, user_id, amount,
auctions: id, object, ... end-date, ...
indexes on bids: auction_id, amount desc
(among others like id's, names ...)

Related

Mysql summary from colums

I need to summary columns together on each row, like a leaderboard. How it looks:
Name | country | track 1 | track 2 | track 3 | Total
John ENG 32 56 24
Peter POL 45 43 35
Two issues here, I could use the
update 'table' set Total = track 1 + track 2 + track 3
BUT it's not always 3 tracks, anywhere from 3 to 20.
Secound if I don't SUM it in mysql I can not sort it when I present data in HTML/php.
Or is there some other smart way to build leaderboards?
You need to redesign your table to have colums for name, country, track number and data Then instead if having a wide table with just 3 track numbers you have a tall, thin table with each row being the data for a given name, country and track.
Then you can summarise using something like
SELECT
country,
name,
sum(data) as total
FROM trackdata
GROUP BY
name,
country
ORDER BY
sum(data) desc
Take a look here where I have made a SQL fiddle showing this working the way you want it
Depending upon your expected data however you might really be better having a separate table for Country, where each country name only appears once (and also for name maybe). For example, if John is always associated with ENG then you have a repeating group and its better to remove that association from the table above which is really about scores on a track not who is in what country and put that into its own table which is then joined to the track data.
A full solution might have the following tables
**Athlete**
athlete_id
athlete_name
(other data about athletes)
**Country**
country_id
country_name
(other data about countries)
**Track**
Track_id
Track_number
(other data about tracks)
**country_athlete** (this joining table allows for the one to many of one country having many athletes
country_athlete_id
country_id
athlete_id
**Times**
country_athlete_id <--- this identifies a given combination of athlete and country
track_id <--- this identifies the track
data <--- this is where you store the actual time
It can get more complex depending on your data, eg can the same track number appear in different countries? if so then you need another joining table to join one track number to many countries.
Alternatively, even with the poor design of my SQL fiddle example, it might be good to make name,country and track a primary key so that you can only ever have one 'data' value for a given combination of name, country and track. However, this decision, and that of normalising your table into multiple joined tables would be based upon the data you expect to get.
But either way as soon as you say 'I don't know how many tracks there will be' then you should start thinking 'each track's data appears in one ROW and not one COLUMN'.
Like others mentioned, you need to redesign your database. You need an One-To-Many relationship between your Leaderboard table and a new Tracks table. This means that one User can have many Tracks, with each track being represented by a record in the Tracks table.
These two databases should be connected by a foreign key, in this case it could be a user_id field.
The total field in the leaderboard table could be updated every time a new track is inserted or updated, or you could have a query similar to the one you wanted. Here is how such a query could look like:
UPDATE leaderboard SET total = (
SELECT SUM(track) FROM tracks WHERE user_id = leaderboard.user_id
)
I recommend you read about database relationships, here is a link:
https://code.tutsplus.com/articles/sql-for-beginners-part-3-database-relationships--net-8561
I still get a lot of issues with this... I don't think that the issue is the database though, I think it's more they way I pressent the date on the web.
I'm able to get all the data etc. The only thing is my is not filling up the right way.
What I do now is like: "SELECT * FROM `times` NATURAL JOIN `players`
Then <?php foreach... ?>
<tr>
<td> <?php echo $row[playerID];?> </td>
<td> <?php echo $row[Time];?> </td>
....
The thing is it's hard to get sorting, order and SUM all in ones with this static table solution.
I searched around for leaderboards and I really don't understand how they build theres with active order etc. like. https://www.pgatour.com/leaderboard.html
How do they build leaderboards like that? With sorting and everything.

Capturing a row's ID to use as a table's name

Just to save anyone reading this time and trouble, DO NOT use this method to store surveys. As pointed out in the answer, this is incredibly poor programming (not to mention dangerous to kitties)
Forgive me if this question is somewhat convoluted. I'm working on building a program that allows users to create surveys and post them for users to take.
Long story short, I have a table that looks like this:
**survey_info**
id bigint(20) Auto_increment Primary Key
title varchar(255)
category bigint(20)
active tinyint(1)
length int(11)
redirect text
now, when a survey is created, a new table is also created that is custom built to hold hte input for that survey. The naming schema I'm using for these new tables is survey_{survey_id}
What I'm hoping to do is in the list of surveys, put the number of responses to a survey to the right of it.
Alright, now my actual question is this, is there a way to retrieve the number of rows in the collection table (survey_id) within the same query I'm using to gather the list of available surveys? I realize that I can do this easily by just using a second query for each survey and grab it's rowcount, but my fear is that the larger the number of surveys the user has, the more time-consuming this process will become. So is there any way to do something like:
SELECT s.id AS id, s.title AS title, c.title AS ctitle, s.active AS active, s.length AS length, s.redirect AS redirect, n.num FROM survey_info s, survey_category c, (SELECT COUNT(*) AS num FROM survey_s.id) n WHERE s.category = c.id;
I just don't know for sure how to use the s.id as part of the other table's name (or if it can even be done)
Any help, or even a point in the right direction would be appreciated!
You need to use one table for all the surveys.
Add newly created id not as a table name but as a survey id in that table.
You create a relational model that will store all surveys options in one table. This is a sample design:
survey
------
id PK
title
surveyOption
--------------
id PK
survey_id FK
option
surveyResponse
--------------
id PK
surveyOptionId FK
response

How can I make this database schema better?

I currently have two tables in which stores the attendances of a student in a course. I have the hub_attendance table which stores the total attendances of a student and the hub_attendance_lesson where it stores the attendance of each lesson that a student has or has not attended. I'm not sure if this is correct or if I'm doing anything wrong, I'm a beginner in databases!
hub_attendance:
id
student_id
course_id
total_lessons
total_lessons_so_far
total_attended
total_absent
total_excused_absent
total_late
total_excused_late
hub_attendance_lesson:
id
lesson_id
course_id
student_id
date
attended
absent
excused_absent
late
excused_late
EDIT:
So I've gotten rid of the first table completely and this is my new single table.
Hub_Attendance:
id
lesson_id
course_id
student_id
date
attendance
As Dutchie432 said, you don't need the first table because it introduces unnecessary redundancy and you can count those statistics on the fly. Such aggregate tables can be a good solution if performance is an issue, but they should be used only as a last resort.
About the second table - you have separate fields attended, absent, excused_absent,
late and excused_late. Aren't these mutually exclusive? So only one of them can be true for one row? If so, you may be better off with one enumeration field called for example attendance, which would take different values for each of those states. In that way you could't have rows where none of the flags, or more than one flag, is set.
Here's what you need:
**Course**
id, name, etc...
**Lesson**
id, courseid, name, etc...
**Attendance**
id, studentid, lessonid, lateness, etc...
**Enrolment**
id, courseid, studentid, startdate, etc...
You need the enrolment table to know that students should be on a course even if they never turn up for lessons. The attendance table will allow you to have many students per lesson and many lessons per student. This is a many-to-many table. Any aggregation and counting can be done in SQL.
If I understand your schema correctly, Your first table can be totally eliminated. You should be able to fetch the totals using MySQL.
select count(id) as total_late from hub_attendance_lesson where late=true and student_id=TheUserId
Remove this first table, every total can be fetch using SQL :
SELECT count(id) AS absent
FROM hub_attendance_lesson
WHERE lesson_id = <your lesson id>
AND absent = <false / true>
I guess you'll be able to adapt this code for your needs.

Items sql table

I am building a textbased game, and I have problem of how to build/structur my SQL table for items.
Item can be anything from weapon, a fruit, armor, etc. But I'm not sure how to properly design this.
For example
Iron Sword Str +4 Health +3
(Or something like that)
But if its a fruit item
Fruit of Health (lol)
+5 health when eated
Any tips or ideas? The question is How do I structure this SQL table?
Store different types of object in different tables.
Give each table the proper columns for the respective kind of object it stores.
CREATE TABLE Weapons (WeaponId INT PRIMARY KEY, Name VARCHAR(20), Strength INT);
CREATE TABLE Foods (FoodId INT PRIMARY KEY, Name VARCHAR(20), HealthBonus INT);
If you want all types of objects to have some common attributes, like weight or purchase price, then you could create a general Items table that has those common attributes.
CREATE TABLE Items (ItemId INT AUTO_INCREMENT PRIMARY KEY,
Weight NUMERIC(9,2), Cost NUMERIC(9,2));
You'd make the WeaponId and FoodId primary keys from the other tables would each match one of the ItemId values in Items. When you want to create a new weapon, you'd first add a row to Items which would generate a new ItemId value, then use that value explicitly as you insert into Weapons.
See the Class Table Inheritance pattern.
Re your question below.
If you are querying for a specific weapon, you can join:
SELECT * FROM Items i JOIN Weapons w ON w.WeaponId = i.ItemId
WHERE w.Name = 'Iron Sword';
If you are query for all items in the character's backpack, you'd have to do multiple joins:
SELECT i.*, COALESCE(w.Name, f.Name, t.Name) AS Name,
CONCAT_WS('/',
IF (w.WeaponId, 'Weapon', NULL),
IF(f.FoodId, 'Food', NULL),
IF(t.TreasureId, 'Treasure', NULL)
) AS ItemType
FROM Items i
LEFT OUTER JOIN Weapons w ON w.WeaponId = i.ItemId
LEFT OUTER JOIN Foods f ON f.FoodId = i.ItemId
LEFT OUTER JOIN Treasure t ON t.TreasureId = i.ItemId
etc.;
If a given Item matches a Weapon but not a Food, then the columns in f.* will be null. Hopefully a given ItemId matches an Id used in only one of the specific subtype tables. On the other hand, it allows a given item to be both a weapon and a food (for instance, vegan cupcakes, which can be effective projectiles ;-).
Sounds like you need a table of attributes (strength, health, etc.). Then a table of the items (name, description, etc) and an association linking the two together (obviously linking by related id's rather than text for normalization, but this is just to demonstrate).
Item Attr Value
Iron Sword Str +4
Iron Sword Hlth +3
Fruit Hlth +5
Right answears given above.. They are different approaches... The second one requires good knwledge of OOP.
I want to mention an other thing, I suggest you read some tutorial on Entity Relational diagram-design. I gues for a game you will probably need to study a few basic things only so it will take you only some hours I guess.
There are many things to consier while designing... for example:
Entity = A thing that can logically stand on its own with its own attributes: Customer, Supplier, Student, Departement are some strong entities etc. Works for, belongs to etc are not entities but relations that associatin entities together.
An entity becomes a table. Strong entities (that have no dependencies) become tables with a simple primary key and usually without accepting any foreign keys. Phone number is not a strong-indepndent entity every time a customer is deleted the phone has no menaing, every time a phone is deleted hte customer has still meaning. Phone is an attribute but because of multiple values it becomes finally a table.
All these are not to tutor er design just to mention that db design in not something to take lightly, it can save you or give you big pain... depends on you.

Managing Foreign Keys

So I have a database with a few tables.
The first table contains the user ID, first name and last name.
The second table contains the user ID, interest ID, and interest rating.
There is another table that has all of the interest ID's.
For every interest ID (even when new ones are added), I need to make sure that each user has an entry for that interest ID (even if its blank, or has defaults).
Will foreign keys help with this scenario? or will I need to use PHP to update each and every record when I add a new key?
Foreign keys are a kind of constraint, so they can only fail when you attempt to add records.
You can accomplish what you are describing with a trigger. I don't know the MySql syntax, but in SQL Server it would look something like this:
CREATE TRIGGER TR_ensure_user_interest ON interest FOR INSERT, UPDATE AS
BEGIN
INSERT user_interest (user_id, interest_id)
SELECT user_id, interest_id
FROM inserted
,user
EXCEPT (SELECT user_id, interest_id)
END
Note that this is a rather inefficient approach, but it should cover many of the cases you're concerned about.
UPDATE: I agree with the others who have observed the design "smell" here. If you can accomplish the required result using JOIN queries, that would be a much more efficient solution. However, I was trying to answer the question actually asked. (Plus, I have been in this situation, where physical records are helpful to other database users who are not adept at compound queries.)
For every interest ID (even when new
ones are added), I need to make sure
that each user has an entry for that
interest ID (even if its blank, or has
defaults).
It sounds like you need an OUTER JOIN (either LEFT or RIGHT) in one of your queries instead.
For example, if you wanted to get the level of interest a particular person has for each interest:
Assuming your tables look like this:
users:
user_id PK
user
user_interests:
user_id PK FK
interest_id PK FK
interest_level
interests:
interest_id PK
interest
SELECT i.interest, ui.interest_level
FROM interests i
INNER JOIN user_interests ui USING (interest_id)
LEFT JOIN users u USING (user_id)
WHERE user_id = ?
? is a placeholder.
Note that ui.interest_level will be null for interests with no data.
It sounds like you are forcing your physical design to mirror your logical design too tightly.
Maybe it would be a good idea to rethink exactly why you need to insert a row for every user in the physical table. Couldn't you just write your queries to assume the default value for an interestID if there isn't an associated interestID for a given user?
"Will foreign keys help with this scenario?"
No.
Your constraint is a sort of "completeness" constraint. It implies that for each new Interest added, there must be as many rows added to the USER_INTEREST table as there are users.
No SQL system is able to enforce that for you. It's up to you to enforce it through code.

Categories