SQL: How to insert multiple values in a cell from existing rows? - sql

My problem is as follows.
I have a database with certain Healthcare services. These services can have 1 or more emails that are stored in HealthcareServiceEmail with a foreign key referencing HealthcareService. I would like to show these emails in the Healthcareservice TABLE.
For this I would need to insert the values from HealthcareserviceEmail INTO the table Healthcareservice where their foreign key matches the key from Healthcareservice.
Because there can be multiple emails I would need to insert multiple values in the same cell. I would also need to insert them into already existing rows from healthcareservice (If I understand correctly). What I have for now is this:
CREATE TABLE IF NOT EXISTS ADMINISTRATION.HealthcareServiceEmail (
id BIGINT NOT NULL,
email VARCHAR(255),
healthcareService_id BIGINT,
name VARCHAR(255),
uuid VARCHAR(255),
PRIMARY KEY (id)
);
ALTER TABLE ADMINISTRATION.HealthcareServiceEmail
ADD FOREIGN KEY (healthcareService_id)
REFERENCES ADMINISTRATION.HealthcareService (id) DEFERRABLE;
INSERT INTO ADMINISTRATION.HealthcareService (email)
SELECT email from ADMINISTRATION.HealthcareServiceEmail
WHERE ADMINISTRATION.HealthcareserviceEmail (healthcareService_id) = ADMINISTRATION.HealthcareService (id)
Now this obviously does not work, but I am not fully sure what to do to solve this as I have looked into SQL but it is definitely not my strong suit.

I would need to insert multiple values in the same cell
This is fundamentally not going to work. One cell, one (possibly NULL) value. The reason to have a second table, in this case ADMINISTRATION.HealthcareServiceEmail, is to be able to represent a one-to-many relationship between the things the database is representing, in this case associating multiple emails with a single Service.
There are other ways to do this; for example, have a column Emails in the Service table, which contains all the emails for that service, concatenated into a single string - but this is a lot harder to work with when it comes to deleting or updating a single email for a service. Whether this is in any way desirable depends on...
I would like to show these emails in the Healthcareservice TABLE
... why you want to do this. If, say, this is so that you can create a UI where each service has all its emails listed, that is work best done in the UI logic. Let the database express the relationships between entities in the most natural way, and let your UI figure out how to arrange them into an aesthetic form.

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');

Inserting test data which references another table without hard coding the foreign key values

I'm trying to write a SQL query that will insert test data into two tables, one of which references the other.
Tables are created from something like the following:
CREATE TABLE address (
address_id INTEGER IDENTITY PRIMARY KEY,
...[irrelevant columns]
);
CREATE TABLE member (
...[irrelevant columns],
address INTEGER,
FOREIGN KEY(address) REFERENCES address(address_id)
);
I want ids in both tables to auto increment, so that I can easily insert new rows later without having to look into the table for ids.
I need to insert some test data into both tables, about 25 rows in each. Hardcoding ids for the insert causes issues with inserting new rows later, as the automatic values for the id columns try and start with 1 (which is already in the database). So I need to let the ids be automatically generated, but I also need to know which ids are in the database for inserting test data into the member database - I don't believe the autogenerated ones are guaranteed to be consecutive, so can't assume I can safely hardcode those.
This is test data - I don't care which record I link each member row I am inserting to, only that there is an address record in the address table with that id.
My thoughts for how to do this so far include:
Insert addresses individually, returning the id, then use that to insert an individual member (cons: potentially messy, not sure of the syntax, harder to see expected sets of addresses/members in the test data)
Do the member insert with a SELECT address_id FROM address WHERE [some condition that will only give one row] for the address column (cons: also a bit messy, involves a quite long statement for something I don't care about)
Is there a neater way around this problem?
I particularly wonder if there is a way to either:
Let the auto increment controlling functions be aware of manually inserted id values, or
Get the list of inserted ids from the address table into a variable which I can use values from in turn to insert members.
Ideally, I'd like this to work with as many (irritatingly slightly different) database engines as possible, but I need to support at least postgresql and sqlite - ideally in a single query, although I could have two separate ones. (I have separate ones for creating the tables, the sole difference being INTEGER GENEREATED BY DEFAULT AS IDENTITY instead of just IDENTITY.)
https://www.postgresql.org/docs/8.1/static/functions-sequence.html
Sounds like LASTVAL() is what you're looking for. It was also work in the real world to maintain transactional consistency between multiple selects, as it's scoped to your sessions last insert.

Creating related tables in SQLite

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.

Creating a table with a field (with a foreign key) which can reference many tables and maintain referencial integrity?

what is the best way of creating a table which can hold a key to a lot of other tables?
As far as I know I have two options:
1) I create a table with a lot of foreign key fields
2) I create two fields, one which indicates the referenced table and another field which holds the primary key of that table.
The latter has a lot of issues due to the fact there's no way to maintain referential integrity (because there's no foreign key to each table).
Besides a link to this table I want to add a description so I can show all notifications in a grid. By clicking a line in the grid I want to open the corresponding program and fix the issue in that program.
It's a bit hard to explain, perhaps this example explains better:
I need to create a system which handles task/notes/notifications for every program in our business application. We have invoices, sales-orders, deliveries, production-orders, etc
Our software detects that something is wrong which any of these. For instance, if the profits on a sales-order are not high enough the order can't be validated automatically. In this case I want to create a notification for the sales-manager so that he can check out what's wrong with the sales-order.
FYI: Iam using Sybase SQL Anywhere 12.
Does it make any sense?
This can be solved in reverse way. Lets say that you have table Alerts where you are going to put all kind of alerts about bad things happened elsewhere. You may reference this table from ALL other tables in your system and create non-mandatory relationship from them. In short it may look like (i'm using MSSQL syntax):
create table Alerts(
ID int not null identity,
SomeInfoAboutTheProblem varchar(255),
constraint PK_Alerts primary key (ID)
)
create table Invoices(
ID....
AlertID int NULL,
....
constraint FK_Invoices2Alerts foreign key (AlertID) references Alerts(ID)
)
In case you cannot modify your tables with business information you may create "extention" table for Alerts that may store some specific problem information and actual reference to the problematic record. For example:
create table Alerts(
ID int not null identity,
SomeInfoAboutTheProblem varchar(255),
constraint PK_Alerts primary key (ID)
)
create table Alerts_for_Invoices(
AlertID int NOT NULL,
InvoiceID int NOT NULL,
SomeAdditionalInvoiceProblemInfo ....,
constraint FK_Alerts_for_Invoices2Alerts foreign key (AlertID) references(ID),
constraint FK_Alerts_for_Invoices2Invoices foreign key (InvoiceID) references Invoices(ID)
)
To show list of problems you may just select general information from Alerts table while opening the dialog you may select all appropriate information regading the problem.

SQLite importing data from a datadump script including primary and foreign keys

I have a SQLite database that makes use of foreign keys, some of which will be autoincremented values. The "core" data the system represents is for example a car. The foreign keys are linking to information about wheels and tyres for example, and I wish to export n cars from one database and import into another.
I want to do this by writing a set of sql statements (i.e a bunch of insert statements) that can be loaded by the importing database, but the key values in the dumped data will not necessarily match up with the existing data (maybe there are duplicates in some of the key values).
What is the best way to deal with this? Is there an easy or recommended way to write the import script so that dependencies on exported key values are removed?
In the example below, a carindex will name a car.
CarPartColours links a single part and with a colour definition. There will be multiple rows in CarPartColours with the same CarID.
I wish to export all the relevant rows from carpartcolours, carindex, parts and colours when the user selects a single row in carindex, and import into another database. The colour definitions in that database may be duplicates (another different issue) or have the same key values as those in the origin db.
CREATE TABLE carindex (
ID integer PRIMARY KEY NOT NULL,
Name varchar(50)
);
CREATE TABLE carpartcolours (
ID integer PRIMARY KEY AUTOINCREMENT NOT NULL,
CarID integer,
PartID integer,
ColourID integer,
/* Foreign keys */
FOREIGN KEY (CarID)
REFERENCES carindex(ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
FOREIGN KEY (PartID)
REFERENCES parts(ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
FOREIGN KEY (ColourID)
REFERENCES colours(ID)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);
CREATE TABLE colours (
ID integer PRIMARY KEY AUTOINCREMENT NOT NULL,
Name varchar(50),
R real,
G real,
B real
);
CREATE TABLE parts (
ID integer PRIMARY KEY AUTOINCREMENT NOT NULL,
Name varchar(50),
Value real,
Manufacturer varchar(50)
);
#Mike I posted a previous answer, and I was on a totally wrong train of thought before, so I'm starting fresh. My apologies.
I would say that you need to make sure you look into database master slave replication, as that's what you're trying to do. You want to replicate the data from the slave to the master. Since you're not going to know which was inserted where when, then you need to look for a collision free key (or try for something collision free). So because you may generate a record in any one database and you may migrate that record to any other database, then you want to generate a UUID style key, and use that in place of a INT AUTOINCREMENT.
This is the only way to do cross database data replication.
Otherwise, you just want to insert into carpartcolours last.
Sorry for the delay in answering your question ...
Try wrapping all your insert statements into transaction:
BEGIN TRANSACTION
// all your inserts go here
END TRANSACTION
I'm not familiar with sqlite per se, but what I have done in the past with similar problems is:
dump out data from origin database, including primary and foreign key values
switch off auto-increment behaviour in target database
import data
switch auto-increment behaviour back on
This may not be possible in sqlite, or may not work because you have pre-existing data with the same primary keys.
In this case, you can import the data from the origin database into temporary tables, and then write scripts to import this into the target database with hand-written SQL, starting at the "furthest" end of the dependency chain. Quite laborious, though.