Creating related tables in SQLite - sql

I am creating related tables in SQLite and am wondering what the most efficient way to make them relate to each other is.
CREATE TABLE cards_name (id INTEGER PRIMARY KEY, name TEXT, rarity TEXT);
CREATE TABLE card_story (id INTEGER PRIMARY KEY, name_id INTEGER, story TEXT);
I have already entered some data for the first table and I was wondering how to add data to the second table without having to look up what the INTEGER PRIMARY KEY is every time (perhaps by using the cards name??)
26|Armorsmith|Rare
27|Auchenai Soulpriest|Rare
28|Avenging Wrath|Epic
29|Bane of Doom|Epic
For instance, I would like to enter the story of Armorsmith as "She accepts guild funds for repairs!" into story TEXT by using her name(Armorsmith) instead of ID(26).
Thanks

The task you are describing should be taken care of on the application level, not on database level.
You can create a GUI where you can select the name of a card, but the underlying value sent back to the database is the card's id and that gets stored in the story table establishing the relationship between the card and the story.

I would like to enter the story of Armorsmith as "She accepts guild funds for repairs!" into story TEXT by using her name(Armorsmith) instead of ID(26).
You can insert into one table from another table. Instead of hard coding the values, you can get them from a select. So long as the rows returned by the select match the rows needed by the insert it'll work.
insert into cards_story
(name_id, story)
select id, :story
from cards_name
where name = :name
The insert needs an ID and a story. The select returns ids and we've added our own text field for the story.
This statement would be executed with two parameters, one containing the text of the story, and one containing the name of the person. So you might write something like this (the exact details depend on your programming language and SQL interface library).
sql.execute(
name: "Armorsmith",
story: "She accepts guild funds for repairs!"
)
Is the equivalent of:
insert into cards_story
(name_id, story)
select id, 'She accepts guild funds for repairs!'
from cards_name
where name = 'Armorsmith'
Note that you'll want to make a few changes to your schema...
Declare name unique else you might get multiple cards for one name.
Like name TEXT UNIQUE.
Since you're looking up cards by name, you probably want to prevent there being multiple cards with the same name. That's just complexity you don't need to deal with.
Declare your foreign keys.
Like name_id INTEGER REFERENCES cards_name(id).
This has multiple benefits. One is keys are automatically indexed, so looking up stories by name_id will be faster.
The other is it enforces "referential integrity" which is a fancy way of saying it makes sure that every story has a name to go with it. If you try to delete a card_name it will balk unless the card_story is deleted first. You can also use things like on delete cascade to do the cleanup for you.
However, SQLite does not have foreign keys on by default. You have to turn them on. It's a very good idea to do so.

Related

How to represent "groups" in SQL?

I code just as a hobby, but always try to learn the "proper" way of doing things. I am very novice when it comes to SQL, and thus I want to give extra background in case I may be approaching the problem completely wrong.
First, I will have a list of "switches" that can be interacted with. The name of each switch will be unique. The DB will need to know how to interact with them (what interface: LPT, GPIO, etc..) and at what "pin" for that interface. The DB doesn't care whether the switch is currently on or off. Thus I plan to have the following table:
switches
--------
<<pk>> name
interface
pin
Now, if the end-user wants to turn off "Light1" or "Light2" they can do so while being agnostic to what type of switch it is or where it's wired.
Where my problem/question comes is I also want to be able to create "groups" to turn on/off multiple related switches at once. Each group will have a unique name (preferably also unique from any name of an individual switch). A switch may exist in zero, one or many groups. Though, my understanding is it would be a bad practice to store a "list" in a column of a SQL table.
An example of groups (using lights as an example), is I may have a group called "Lights" that contains the name of every light switch. I may also have a group named "KitchenLights" which contains the name of every light switch in the kitchen. The expectation is the lists will be manually maintained if related switches are newly added or removed.
One approach that I was thinking is just added more columns to the "switches" table to describe what "type" of switch (light) and "where" it is (kitchen) -- but then the types groups would be "hard coded." If I later decided I wanted to group them by which floor they're on, it would be structure change to add a new column and code change.
So, what are the suggestions for how to approach this?
Thanks!
You can try following approach:
create table switches
(name varchar(100) primary key,
interface int,
pin varchar(100));
Create table groups
( group_id int primary key,
group_name varchar (100));
Create table sub_group
( group_id int,
switch_id varchar(100) ,
constraint groups_fk FOREIGN KEY (group_id) references groups(group_id),
constraint switches_fk FOREIGN KEY (switch_id ) references switches(name));
insert into switches values
('Light1',123,'xyz'),
('Light2',456,'abcd'),
('Light3',789,'testpin');
insert into groups values
(1,'Group1'),
(2,'Group2'),
(3,'Group3');
insert into sub_group values
( 1,'Light1'),(1,'Light2'),
(2,'Light1'),(2,'Light3');

is it necessary to have foreign key for simple tables

have a table called RoundTable
It has the following columns
RoundName
RoundDescription
RoundType
RoundLogo
Now the RoundType will be having values like "Team", "Individual", "Quiz"
is it necessary to have a one more table called "RoundTypes" with columns
TypeID
RoundType
and remove the RoundType from the rounds table and have a column "TypeID" which has a foreign key to this RoundType table?
Some say that if you have the RoundType in same table it is like hard-coding as there will be lot of round types in future.
is it like if there are going to be only 2-3 round types, i need not have foreign key??
Is it necessary? Obviously not. SQL works fine either way. In a properly defined database, you would do one of two things for RoundType:
Have a lookup table
Have a constraint that checks that values are within an agreed upon set (and I would put enums into this category)
If you have a lookup table, I would advocate having an auto-incremented id (called RoundTypeId) for it. Remember, that in a larger database, such a table would often have more than two columns:
CreatedAt -- when it was created
CreatedBy -- who created it
CreatedOn -- where it was created (important for distributed systems)
Long name
In a more advanced system, you might also need to internationalize the system -- that is, make it work for multiple languages. Then you would be looking up the actual string value in other tables.
is it like if there are going to be only 2-3 round types, i need not
have foreign key??
Usually it's just the opposite: If you have a different value for most of the records (like in a "lastName" column) you won't use a lookup table.
If, however, you know that you will have a limited set of allowed/possible values, a lookup table referenced via a foreign key is probably the better solution.
Maybe read up on "database normalization", starting perhaps # Wikipedia.
Actually you need to have separate table if you have following association between entities,
One to many
Many to many
because of virtue of these association simple DBMS becomes **R**DBMS ( Relation .)
Now ask simple question,
Whether my single record in round table have multiple roundTypes?
If so.. Make a new table and have foreign key in ROUNDTable.
Otherwise no.
yeah I think you should normalize it. Because if you will not do so then definitely you have to enter the round types (value) again and again for each record which is not good practice at all in case if you have large data. so i will suggest you to make another table
however later on you can make a view to get the desired result as fallow
create view vw_anyname
as
select RoundName, RoundDescription , RoundLogo, RoundType from roundtable join tblroundtype
on roundtable.TypeID = tblroundtype .typeid
select * from vw_anyname

Generate sequential number with a prefix

I need to assign a unique number to each "customer". Basically an account number or so to speak. I need to generate a sequential number with a prefix... say... 10001111 to eventually 19999999. The numbers need to be unique. I know how to create a random number but those numbers must be unique and can't be repeated so I am stuck with how to even begin with the programming logic. I found some C# that would help but I am programming in VB.NET. Any help would be appreciated!
Honestly, I don't see why you need to do anything more complicated than an Identity Column in SQL Server.
CREATE TABLE Persons
(
P_Id int PRIMARY KEY IDENTITY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
Source: W3 Schools
You can then pull the customer data back and pre-pend a prefix to this either static or dynamically.
A static example would be
SELECT 'CUST-' + P_Id [CustomerNumber], LastName
FROM Persons
But nothing is stopping you from adding the prefix in as a column an dynamically joining them (if you need to store multiple prefixes).
At the end of the day, you'll need a persistent store to ensure you're getting a unique number. Instead of reinventing the wheel on this you can leverage the DB server, which is written for this purpose.
You can also have a table in the DB whose job is to store the latest ID number and you can manually increment and update that, but I'm not a huge fan of that. It is too messy.
One common way to do this kind of thing is to generate all of the possibilities at once, and store them in a list. When you want to create a new customer, choose a random number from the list and then remove it from that list so that it can't be used again. I don't know how practical this would be in your scenario.

SQL Newbie: Use a foreign key for a lookup table being used like an enum() field?

Say I have field Ice_Cream.flavor, with the current choices in lookup table Flavor.flavor.
I use Flavor.flavor like an enum() list, storing the value, not the record ID, in Ice_Cream.flavor. If Flavor.flavor changes, I don't want to update Ice_Cream:flavor. I want it to stay as created.
Should I set up Ice_Cream.Flavor as a foreign key, so I can see the source of the values in my ER diagram, or not?
If you want Ice_Cream.flavor to stay as created even if there is no matching record in Flavor (which is what your question sounds like) then you cannot create a FOREIGN KEY relationship, it will not allow that condition to occur in your database.
Furthermore, if you're storing the actual text Flavor.Flavor string in Ice_Cream.Flavor, there's no particular reason to have a separate RecordID column in Flavor.
IMHO, you do not need a FK here except if you have additional informations about a flavor in the Flavor table beside the name in the column flavor. It is the case because you do not keep an ID, you keep the name AND you want to keep the old value.
I also supposed that you do not want to keep old flavors in the Flavor table or elsewhere except in the Ice_Cream table.
Last but not least, a FK would require that any flavor stored in Ice_Cream.flavor exists in the Flavor table. It is not the case if I understand correctly your question.

Creating database tables with "either or" type fields

I have a database that tracks players through their attempts at a game. To accomplish this, I keep a table of users and store the attempts in a separate table. The schema for these tables is:
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- the local unique ID for this user
name TEXT UNIQUE, -- a self-chosen username for the user
first_name TEXT, -- the user's first name
last_name TEXT, -- the user's last name
email TEXT, -- the user's email address
phone TEXT -- the user's phone number
);
CREATE TABLE trials (
timestamp TIMESTAMP PRIMARY KEY, -- the time the trial took place
userid BIGINT, -- the ID of the user who completed the trial
score NUMERIC, -- the score for the trial
level NUMERIC, -- the difficulty level the trial ran at
penalties NUMERIC -- the number of penalties accrued in the trial
);
Now I need to be able to store attempts that come from "transient" users. These attempts should not be linked back to an existing user. However, these transient users will still be able to enter a name that displays in the results. This name is not required to be unique in the table, since it does not represent a "real" user.
My first thought was to create a new field in the trials table called name. If userid is null, I would know it is a transient user, but I would still be able to show the name fields in the results. This approach doesn't quite smell right, and it seems like it will make my queries a bit more complicated. Additionally, it seems like I'm duplicating data in a sense.
Another thought was to replace userid with a useref text field that would be some kind of formatted string representing the user. For example, if the value were enclosed in curly braces, I would know it's an ID, i.e. {58199204}. If the value were not enclosed, I would treat it as a transient user. This more accurately represents what I'm trying to do conceptually (i.e. it's either an ID or a transient user string), but it would really complicate my queries.
I'm using SQLite for the backend... It lacks some of the extended features of SQL Server or MySQL.
Any thoughts on these or another approach to the problem?
Without more information about why a transient user can use but not exist in the system, I concur with your idea to:
Add a NAME column to the TRIALS table
Make the USER_ID column in the TRIALS table nullable/optional in order to indicate transient user status
If you could allow a transient user to exist in the system, I would recommend:
Creating a USER_TYPE_CODE table
Update the USERS table to include the USER_TYPE_CODE column (w/ foreign key reference to the USER_TYPE_CODE table)
You can either create a UserType field in the users table, and add "transient" users to the Users table, but this might increase the size of the Users table, or create a UserType field on the Trials table and create an additional TransientUsers table.
This will allow you to distinguish the difference of userid with the UserType field.
I'd like to point out that you really shouldn't use the formatted string approach. What happens if a user finds a bugged input port into your database and inputs "{8437101}" (or whatever user ID they want)?
SQLite lets you mix types in a field. I'd suggest you do as you were thinking, but without the braces. Disallow numeric names. If the userid is a number, which is exactly when it matches an id in the users table, it is a user id. If not it's the name of a transient user.