Creating table when each object may have a list of values - sql

First I've created a table with information on stores and transactions with the following query:
CREATE TABLE main.store_transactions
(
store_id varchar(100) NOT NULL,
store_name varchar(100),
store_transaction_id varchar(100),
transaction_name varchar(100),
transaction_date timestamp,
transaction_info varchar(200),
primary_key(store_id)
)
But then I realized that the same store may have various transactions related to it, not just one. How should I implement table creation in this case?
One thing that comes to mind is to create a separate table with transactions, each transaction having store_id as a foreign key. And then just join when needed.
How is it possible to implement it in a single table?

Well, the most elegant way would be indeed to create a satelite table for your stores and reference it to the store_transactions table, e.g:
CREATE TABLE stores
(
store_id varchar(100) NOT NULL PRIMARY KEY,
store_name varchar(100)
);
CREATE TABLE store_transactions
(
store_id varchar(100) NOT NULL REFERENCES stores(store_id),
store_transaction_id varchar(100),
transaction_name varchar(100),
transaction_date timestamp,
transaction_info varchar(200)
);
With this structure you will have many transactions to a single store.
There are other less appealing options, such as customizing a data type for stores and creating an array of it in the table store_transactions. But regarding the costly maintainability of such approach, I would definitely discourage it.

Related

How do I create a IF statement creating a table in Postgres?

I'm creating a table and I need a check constraint to validate the posibles values given a string value. I'm creating this table:
CREATE TABLE cat_accident (
acc_type VARCHAR(30) NOT NULL CHECK(acc_type = 'Home accident' OR acc_type = 'Work accident'),
acc_descrip VARCHAR(30) NOT NULL
);
So basically I want to validate if acc_type is equal to Home accident, then acc_descrip can be or 'Intoxication' OR 'burns' OR 'Kitchen wound', OR if acc_type is equal to Work Accident, then acc_descrip can be OR 'freezing' OR 'electrocution'.
How do I write that constraint?
Use a CHECK constraint with a CASE expression:
CREATE TABLE cat_accident (
acc_type VARCHAR(30) NOT NULL,
acc_descrip VARCHAR(30) NOT NULL
CHECK(
CASE acc_type
WHEN 'Home accident' THEN acc_descrip IN ('Intoxication', 'burns', 'Kitchen wound')
WHEN 'Work accident' THEN acc_descrip IN ('freezing', 'electrocution')
END
)
);
See the demo.
I'd suggest implementing this with a lookup table:
CREATE TABLE l_accident_description(
description_id VARCHAR(5) PRIMARY KEY,
description_full VARCHAR(30) NOT NULL UNIQUE,
location VARCHAR(30)
);
INSERT INTO l_accident_description
(description_id,description_full,location)
VALUES
('INTOX','Intoxication','Home Accident'),
('BURNS','Burns','Home Accident'),
('K_WND','Kitchen wound','Home Accident'),
('FREEZ','Freezing','Work Accident'),
('ELECT','Electrocution','Work Accident');
That way you can encode the relationship you want to encode into cat_accident, but if the details ever change, it's only a matter of inserting/deleting/updating rows in your lookup table. This implementation has the added benefit that you're not storing as much data repetitively in your table (just a VARCHAR(5) code rather than a VARCHAR(30) string). The table construction then becomes (with added primary key):
CREATE TABLE cat_accident (
cat_accident_id PRIMARY KEY,
acc_descrip VARCHAR(5) NOT NULL REFERENCES l_accident_description(description_id)
);
Any time you wanted to know whether the accident Home/Work, this could be accomplished with a query joining the lookup table. Joining lookup tables is more in the spirit of good database construction, rather than hard-coding checks to tables that may easily change or grow more complex as the database grows.
In fact, the ideal solution might be to create two lookup tables here, with l_accident_description in turn referencing a location lookup, but for simplicity's sake I've shown how it might be accomplished with one.

Adding Columns to Multiple Tables in SQL

I just created a database and then added a couple of hundred tables with a script like this:
CREATE TABLE CapBond
(
[timestamp] varchar(50),
[Reward] varchar(50),
[Award] varchar(50),
[Fact] varchar(50)
)
CREATE TABLE Values
(
[timestamp] varchar(50),
[Name] varchar(50),
[Test] varchar(50),
[Read] varchar(50),
[Parameters] varchar(50)
)
I realize I forgot to add two columns to each table. One for the PK and one for an FK that points back to a 'master' table.
Is there an easy way to insert columns without having to drop the DB and recreate it? Preferably with the columns inserted as the first two columns in the table?
Yes. In mysql you have the alter table command for this purpose. Check out this page for more detailed explanation
https://www.sqlservertutorial.net/sql-server-basics/sql-server-alter-table-add-column/ .
And here is the solution for the ordering of the columns
https://www.mysqltutorial.org/mysql-add-column/

Enforcing referential integrity from one table to any table

I have a variety of tables that represent business objects, e.g. Products, People, Locations and I'm wanting to add a Tags table (as in taxonomy).
CREATE TABLE Tags (
tagId bigint IDENTITY,
name nvarchar(50)
)
How can I allow multiple tags to be applied to multiple types of entities in a way that allows the DBMS to enforce referential integrity without needing a linking table like this:
CREATE TABLE TagUse (
tagId bigint,
productId bigint NULL,
personId bigint NULL,
locationId bigint NULL,
...
whateverId bigint NULL
)
Or worse:
CREATE TABLE PersonTags (
tagId bigint,
personId bigint
)
CREATE TABLE LocationTags (
tagId bigint,
locationId bigint
)
...
CREATE TABLE WhateverTags (
tagId bigint,
whateverId bigint
)
I just thought of a third option: rather than having separate *Tags tables for each entity, each entity can be thought of inheriting from "Taggable" which is then referenced-to by the child tables:
CREATE TABLE Taggable (
taggableId bigint,
tagId bigint
)
CREATE TABLE Persons (
personId bigint,
...
taggableId bigint
)
You could use a sequence object:
CREATE TABLE [TaggableObjects] (
objectId BIGINT IDENTITY(1,1)
)
CREATE TABLE [Persons] (
objectId BIGINT, -- referencing Objects.objectId
name VARCHAR(50)
)
CREATE TABLE [Locations] (
objectId BIGINT, -- referencing Objects.objectId
country VARCHAR(50)
)
In programming languages like Java and C# you'd call Persons and Locations an extension of TaggableObject.
Following this you could implement the Tags as:
CREATE TABLE [Tags] (
tagId BIGINT IDENTITY(1,1),
objectId BIGINT
)
Though the problem with an implementation like this one would be that you have to figure out the best way to identify of what type Tags.objectId is.
Note that depending on which engine you'll be using, many support some sort of functionality to more easily implement a sequence object, you might want to right up on it.

Selecting data from a database via a joined table

I'm currently making a website that is used to advertise car sharing for festivals. I need to list all trips which are currently assigned to a user but seeing as the database relationship would be many to many I have had to make a client_trip table.
My question:
How would I select trips from the trip table based on the information in my client_trip table?
I'm currently using PostgreSQL and Java servlets. Thanks very much for any help. :)
CREATE TABLE users
(
user_id SERIAL,
user_username VARCHAR (20),
user_firstname VARCHAR(20),
user_surname VARCHAR(20),
user_password VARCHAR(50),
user_email VARCHAR(100),
user_role VARCHAR(20),
PRIMARY KEY(user_id)
);
CREATE TABLE trips
(
trip_id SERIAL,
trip_name VARCHAR (100),
trip_user_username VARCHAR (50),
trip_festival_id SERIAL REFERENCES festivals(festival_id),
trip_festival_name VARCHAR(100),
trip_depart_date DATE,
trip_return_date DATE,
trip_spaces INT,
trip_cost Decimal (19,2),
trip_desc VARCHAR,
PRIMARY KEY(trip_id)
);
how would I select trips from the trip table based on the information in my client_trip
With a given user_id:
SELECT t.*
FROM trips t
JOIN client_trip ct USING (trip_id)
WHERE ct.user_id = ??

store two values in one field sql

I have to create a table in sql where one of the columns stores awards for a movie. The schema says it should store something like Oscar, screenplay. Is it possible to store two values in the same field in SQL. If so what datatype would that be and how would you query the table for it?
It's a horrible design pattern to store more than one piece of data in a single column in a relational database. The exact design of your system depends on several things, but here is one possible way to model it:
CREATE TABLE Movie_Awards (
movie_id INT NOT NULL,
award_id INT NOT NULL,
CONSTRAINT PK_Movie_Awards PRIMARY KEY CLUSTERED (movie_id, award_id)
)
CREATE TABLE Movies (
movie_id INT NOT NULL,
title VARCHAR(50) NOT NULL,
year_released SMALLINT NULL,
...
CONSTRAINT PK_Movies PRIMARY KEY CLUSTERED (movie_id)
)
CREATE TABLE Awards (
award_id INT NOT NULL,
ceremony_id INT NOT NULL,
name VARCHAR(50) NOT NULL, -- Ex: Best Picture
CONSTRAINT PK_Awards PRIMARY KEY CLUSTERED (award_id)
)
CREATE TABLE Ceremonies (
ceremony_id INT NOT NULL,
name VARCHAR(50) NOT NULL, -- Ex: "Academy Awards"
nickname VARCHAR(50) NULL, -- Ex: "Oscars"
CONSTRAINT PK_Ceremonies PRIMARY KEY CLUSTERED (ceremony_id)
)
I didn't include Foreign Key constraints here, but hopefully they should be pretty obvious.
Anything's possible; that doesn't mean it's a good idea :)
Far better to normalize your structure and store types like so:
AwardTypes:
AwardTypeID
AwardTypeName
Movies:
MovieID
MovieName
MovieAwardType:
MovieID
AwardTypeID
You can serialize your data in Json format,store Json string, and deselialize on read. More sefer than using your own format
Data presentation does't have to be so close tied with phisical data organisation. Wouldn't it be bether to store these two data in two separate columns and then just do some kind of concatenation at the display time?
It is much less painfull to join data than to split it, if you happen to need just a screenplay, one day...