I have several tables of weight/price pairs with the following format:
(example for two tables, I have several such tables)
table 1: table 2:
weight price weight price
5 7 5 4
10 9 10 7
15 14 15 11
20 15 20 14
... ...
Each weight/price table has the same amount of rows but it should be possible to edit the values when needed. It should also be possible to add new tables at a later time with as little trouble as possible.
I would like for the table to be almost like an attribute of another entity. Is there a way to do such a thing? Some suggest to simply store the files on the disk and read them when needed, but that solution is not perfect for me, since I would like to edit the values on occasion.
What is the correct structure to store such data?
In SQL you could simply do something like this (assuming "Product" is the thing that identifies each set of weight/price pairs and assuming weight determines price):
CREATE TABLE ProductWeightPrice
(Product VARCHAR(20) NOT NULL,
Weight INT NOT NULL,
Price INT NOT NULL,
PRIMARY KEY (Product,Weight));
If you need more help then please say what DBMS you are using.
Would it work for you to have a "table number" field? So it becomes:
product_id,
table_number,
weight,
price
With a primary key on product_id, table_number.
Now it isn't a "table number" any more, but more a "pair number", or similar, so you could change the names to be more meaningful.
Related
Caveat: very new to database design/modeling, so bear with me :)
I'm trying to design a simple database that stores information about images in an archive. Along with file_name (which is one distinct string), I have fields like genre and starring where each field might contains multiple strings (if an image is associated with multiple genres, and/or if an image has multiple actors in it).
Right now the database is just a single table keyed on file_name, and the fields like starring and genre just have multiple comma-separated values stored. I can query it fine by using wildcards and like and in operators, but I'm wondering if there's a more elegant way to break out the data such that it is easier to use/query. For instance, I'd like to be able to find how many unique actors are represented in the archive, but I don't think that's possible with the current model.
I realize this is a pretty elementary question about data modeling, but any guidance anyone can provide or reading you can direct me to would be greatly appreciated!
Thanks!
You need to create extra tables in order to stick with the normalization. In your situation you need 4 extra tables to represent these n->m relations(2 extra would be enough if the relations were 1->n).
Tables:
image(id, file_name)
genre(id, name)
image_genres(image_id, genre_id)
stars(id, name, ...)
image_stars(image_id, star_id)
And some data in tables:
image table
id
file_name
1
/users/home/song/empire.png
2
/users/home/song/promiscuous.png
genre table
id
name
1
pop
2
blues
3
rock
image_genres table
image_id
genre_id
1
2
1
3
2
1
stars table
id
name
1
Jay-Z
2
Alicia Keys
3
Nelly Furtado
4
Timbaland
image_stars table
image_id
star_id
1
1
1
2
2
3
2
4
For unique actor count in database you can simply run the sql query below
SELECT COUNT(name) FROM stars
This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 9 years ago.
I have results data like this:
1. account, name, #, etc
2. account, name, #, etc
...
10. account, name, #, etc
I have approximately 1 set of results data generated each week.
Currently it's stored like so:
DATETIME DATA_BLOB
Which is annoying because I can't query any of the data without parsing the BLOB into a custom object. I'm thinking of changing this.
I'm thinking of having one giant table:
DATETIME RANK ACCOUNT NAME NUMBER ... ETC
date1 1 user1 nn #
date1 2 user2 nn #
...
date1 10 userN nn #
date2 1 user5 nn #
date2 2 user12 nn #
...
date2 10 userX nn #
I don't know anything about database design principles, so can someone give me feedback on whether this is a good approach or there might be a better one?
Thanks
I think it is ok to have a table like that, if there are not one-to-many relationships. In that case, it would be more efficient to have multiple tables like in my example below. Here are some general tips as well:
Tip: Good practice My professor told me that it's always good to have an "ID" column, which is a unique number identifier for each item in the table (1, 2, 3… etc.). (Perhaps that was the intent of your "Number" column.) I think SQLite forces each table to have an ID column anyways.
Tip: Saving storage space - Also, if there is a one-to-many relationship (example: one name has many accounts) then it might save space to have a separate table for the accounts, and then store the ID of the name in the first table- so that way you are storing many ints instead of duplicate strings.
Tip: Efficiency - Some databases have specific frameworks designed to handle relationships such as many-to-one or many-to-many, so if you use their framework for that (I don't remember exactly how to do it) it will probably work more efficiently.
Tip: Saving storage space - If you make your own ID column it might be a waste if it automatically includes an "ID" column anyways - so you might want to check for that possibility.
Conceptual Example: (Storing multiple accounts for the same name)
Poor Solution:
Storing everything in 1 table (inefficient, because it duplicates Bob's name, rank, and datetime):
ID NAME RANK DATETIME ACCOUNT
1 Bob 1 date1 bob_account_1
2 Joe 2 date2 user2_joe
3 Bob 1 date1 bob_account_2
4 Bob 1 date1 bobs_third_account
Better Solution: Having 2 tables to prevent duplicated information (Also demonstrates the usefulness of ID's). I named the 2 tables "Account" and "Name."
Table 1: "Account" (Note that NAME_ID refers to the ID column of Table 2)
ID NAME_ID ACCOUNT
1 1 bob_account_1
2 2 user2_joe
3 1 bob_account_2
4 1 bobs_third_account
Table 2: "Name"
ID NAME RANK DATETIME
1 Bob 1 date1
2 Joe 2 date2
I'm not a database expert so this is just some of what I learned in my internet programming class. I hope this helps lead you in the right direction in further research.
this question came up based on the responses I got for the question
Getting weird issue with TO_NUMBER function in Oracle
As everyone suggested that storing Numeric values in VARCHAR2 columns is not a good practice (which I totally agree with), I am wondering about a basic Design choice our team has made and whether there are better way to design.
Problem Statement : We Have many tables where we want to give certain number of custom fields. The number of required custom fields is known, but what kind of attribute is mapped to the column is available to the user
E.g. I am putting down a hypothetical scenario below
Say you have a laptop which stores 50 attribute values for every laptop record. Each laptop attributes are created by the some admin who creates the laptop.
A user created a laptop product lets say lap1 with attributes String, String, numeric, numeric, String
Second user created laptop lap2 with attributes String,numeric,String,String,numeric
Currently there data in our design gets persisted as following
Laptop Table
Id Name field1 field2 field3 field4 field5
1 lap1 lappy lappy 12 13 lappy
2 lap2 lappy2 13 lappy2 lapp2 12
This example kind of simulates our requirement and our design
Now here if somebody is lookinup records for lap2 table doing a comparison on field2, We need to apply TO_NUMBER.
select * from laptop
where name='lap2'
and TO_NUMBER(field2) < 15
TO_NUMBER fails in some cases when query plan decides to first apply to_number instead of the other filter.
QUESTIONS
Is this a valid design?
What are the other alternative ways to solve this problem?
One of our team mates suggested creating tables on the fly for such cases. Is that a good idea?
How do popular ORM tools give custom fields or flex fields handling?
I hope I was able to make sense in the question.
Sorry for such a long text..
This causes us to use TO_NUMBER when queryio
This is a common problem and there is no perfect solution. A couple of solutions:
1.
Define X fields of type varchar2, Y fields of type number and Z fields of type date. That comes out as potentially 3 times the number of custom fields but you will never have any conversion problem anymore.
Your example would come out like this:
Id Name field_char1 field2_char2 field_char3 ... field_num1 field_num2 ...
1 lap1 lappy lappy lappy ... 12 13
2 lap2 lappy2 lappy2 lapp2 ... 13 12
In your example you have the same number of numeric values and character values on both rows but it doesn't have to be this way: the third row could have no numeric field for example.
2.
Define X fields of type varchar2 and have apply a bijective function to store number or date field (for example Date could be stored as YYYYMMDDHH24miss). You will also need an extra field that will define the context of the row. You would apply the to_number or to_char function only when the rows are of the good type.
Your example:
Id Name context field1 field2 field3 field4 field5
1 lap1 type A lappy lappy 12 13 lappy
2 lap2 type B lappy2 13 lappy2 lapp2 12
You could query the table using DECODE or CASE:
SELECT *
FROM laptop
WHERE CASE WHEN context = 'TYPE A' THEN to_number(field3) END = 12
The second design is the one used in the Oracle Financials ERP (among others). The context allows you to define CHECK constraints with this design (for example CHECK (CASE WHEN context = 'TYPE A' THEN to_number(field3) > 0) to ensure integrity.
This is a common scenario with shrink-wrapped apps, where it represents the only opportunity for customizing the data model. But from a purist point of view it is bad practice. Because if a column can contain '27-MAY-2010' or 178.50 or 'Red badger' then clearly it is dependent on something external to the database to give it meaning.
But using an XMLType is even worse because you lose what little structure you have. It becomes difficult to query on the flexible columns. Still there are some scenarios where this is the appropriate solution: mainly when we're not interested in the individual elements, just the collection of properties.
So, what is the best way of dealing with it? Customised functions to go with your custom columns:
SQL> create or replace function get_number
2 ( p_str in varchar2 )
3 return number
4 deterministic
5 is
6 return_value number;
7 begin
8 begin
9 return_value := to_number(trim(p_str));
10 exception
11 when others then
12 return_value := null;
13 end;
14 return return_value;
15 end;
16 /
Function created.
SQL>
We can build a function-based on this column, for performance:
SQL> create index t42_flex_idx on t42 ( get_number( flex_col))
2 /
Index created.
SQL>
So given this test data ....
SQL> select * from t42
2 /
ID FLEX_COL
---------- ------------------------------
1 27-MAY-2010
2 138.50
3 Red badger
2 23
SQL>
... here's how it works:
SQL> select * from t42
2 where get_number(flex_col) < 50
3 /
ID FLEX_COL
---------- ------------------------------
2 23
SQL>
If all of the column types are decided at the time the table is created, then generating tables on the fly sounds good to me.
However, if two users are using the same table with different fields, you could create new tables just for the custom fields and join them to the main table. This is more of an object oriented approach.
Could you create an XML graph in the code layer and store it in a SYS.XMLTYPE field type?
http://www.oracle-base.com/articles/9i/XMLTypeDatatype.php
This would allow you to strongly type (in XML) your values and retain meaningful structure.
alt text http://produits-lemieux.com/database.jpg
This is basicly my database structure
one product (let say soap) will have many retail selling size
1 liter
4 liters
20 liters
In my "produit" database I will have the soap item (id #1)
In the size database i will have many size availible :
1liter
4liter
20liter
How not to duplicate the product 3 time with a different size... i like to be able to have check box in the product size of all the size available in the database and check if yes or no (boolean)
The answer a got is perfect, but how to have the option like that :
soap [x] 1 liter , [ ] 4 liter , [x] 20 liter
I'm not sure I understand your exact scenario, but to create a many-to-many relationship, you simply create a "relationship table", in which you store id's for the two records you want to link.
Example:
Products
********
ProductID (PK)
Price
Retailers
*********
RetailerID (PK)
Name
ProductRetailerRelationships
****************************
ProductID
RetailerID
A many-to-many relationship is almost always modeled using an intermediate table. For your example,
Product
--------
prod_numero
...
Size
--------
size_numero
...
Product_Size
--------
prod_numero
size_numero
...
The Size table would contain particular sizes (say, 10 liter) and the Product_Size table creates a Product and Size pairing.
You Will need an Intermediary, or "Join" Table
ProductSizes
.......................
ProductID
SizeID
One record for each product-size combination
Based on the answers, here is the database tables layout as proposed, it look complicated to me, but are you sure it is the way to do this, the BEST solution ?
alt text http://produits-lemieux.com/database2.jpg
I have to add a coupon table to my db. There are 3 types of coupons : percentage, amount or 2 for 1.
So far I've come up with a coupon table that contains these 3 fields. If there's a percentage value not set to null then it's this kind of coupon.
I feel it's not the proper way to do it. Should I create a CouponType table and how would you see it? Where would you store these values?
Any help or cue appreciated!
Thanks,
Teebot
You're correct, I think a CouponType table would be fit for your problem.
Two tables: Coupons and CouponTypes. Store the CouponTypeId inside the Coupons table.
So for an example, you'll have a Coupon record called "50% off", if would reference the percent off CouponType record and from there you could determine the logic to take 50% off the cost of the item.
So now you can create unlimited coupons, if it's a dollar amount coupon type it will take the "amount" column and treat it as a dollar amount. If it's a percent off it will treat it as a percentage and if it's an "x for 1" deal, it will treat the value as x.
- Table Coupons
- ID
- name
- coupon_type_id # (or whatever fits your style guidelines)
- amount # Example: 10.00 (treated as $10 off for amount type, treated as
# 10% for percent type or 10 for 1 with the final type)
- expiration_date
- Table CouponTypes
- ID
- type # (amount, percent, <whatever you decided to call the 2 for 1> :))
In the future you might have much more different coupon types. You could also have different business logic associated with them - you never know. It's always useful to do the things right in this case, so yes, definitely, create a coupon type field and an associated dictionary table to go with it.
I would definitely create a CouponType lookup table. That way you avoid all the NULL's and allow for more coupon types in the future.
Coupon
coupon_id INT
name VARCHAR
coupon_type_id INT <- Foreign Key
CouponType
coupon_type_id INT
type_description VARCHAR
...
Or I suppose you could have a coupon type column in your coupon table CHAR(1)