Same attributes, different tables in one database in SQLite - sqlite

I am just new in SQLite and I have this assignment in creating database schema using the said program.
I just want to ask if it is allowed to give a same attributes present in different tables inside a single database. Let me give the SQLite statements of two tables in one database.
BEGIN TRANSACTION;
/* Create a table called Employee */
CREATE TABLE Employee(Name text, Phone_number varchar);
/* Create a table called Company */
CREATE TABLE Company(Name text, Country text);
I am referring to attribute Name which appears twice in two tables. Will it affect or distorts some of the SQL queries execution in the database?

If you had tried it (in the command-line shell or on SQLFiddle), you would have found out that it is allowed.
However, it can affect your queries.
When you join these two tables, you have to explicitly specifiy which table's column you want:
CREATE TABLE Employee(ID, CompanyID, Name, Phone_number);
CREATE TABLE Company(ID, Name, Country);
SELECT Company.Name,
Employee.Name,
Phone_number
FROM Company
JOIN Employee ON Company.ID = Employee.CompanyID;
On the other hand, if you have a foreign key relationship, using the same name in both tables allows you to simplify the join condition:
CREATE TABLE Employee(EmployeeID, CompanyID, Name, Phone_number);
CREATE TABLE Company(CompanyID, Name, Country);
SELECT Company.Name,
Employee.Name,
Phone_number
FROM Company
JOIN Employee USING (CompanyID);

Related

How to UPDATE a table by using __rowid__ of another table in sqlite3

I am doing CRUD operations using __rowid__ which comes default with the sqlite table. I don't have separate columns for ID's in any of my tables.
My create, read and delete operations are done.
I am searching the database by customer's name.
TABLES
UPDATE query for the customers table
cursor.execute("""
SELECT * FROM customers
WHERE name = ?""", (name_variable.get(),))
cursor.execute("""
UPDATE customers SET
'contact' = ?,
'mail' = ?,
'address' = ?
WHERE name = ?
""",
(
contact_variable.get(),
mail_variable.get(),
address_variable.get(),
name_variable.get()
)
)
My issue is with updating the services & charges table.
What I want is if user changes John's information then how do I UPDATE only John's data to these two tables using __rowid__. I don't understand how to execute that query.
(I am using sqlite3 version 3.31.1 on Ubuntu 20.04).
According to the schema you have shown there is no relationship between Customers, Services and Charges so updating a Customer has no bearing on the other tables. As such you probably want a relationship and the implication of you saying
then how do I UPDATE only John's data to these two tables using rowid
The answer to that is the rowid column, as there are not relationships, does not do anything other than uniquely identify a row in the respective tables.
So first you need to define the relationships which will require either
a column in each of the two tables (services and charges) to cater for a parent (customer) with children (services will be children of a customer and charges will be children of a customer) aka two one (customer) to many (services and charges) relationship, or
a mapping reference table if you need a many-many relationship.
Typically the most efficient way of mapping/reference/relating/linking/associating children to parents is to utilises the always present (but normally hidden) rowid by aliasing it to column name (e.g. id INTEGER PRIMARY KEY).
As such you probably want you table definitions to be something like:-
CREATE TABLE IF NOT EXISTS customers (
customer_id INTEGER PRIMARY KEY,
name TEXT,
contact TEXT,
mail TEXT,
address TEXT
);
the customer_id is an alias of the rowid column
then :-
CREATE TABLE IF NOT EXISTS services (
serviceid INTEGER PRIMARY KEY,
service TEXT, subservice TEXT,
customer_id INTEGER REFERENCES customers(customer_id) ON DELETE CASCADE ON UPDATE CASCADE
);
the service_id column is an alias of the rowid column
the customer_id column references the parent, i.e. the customer to whom the services belongs to.
the REFERENCES keyword along with the table and the associated column defines a constraint that says the customer_id column MUST be a value that exists in the customer_id column of the customers table (i.e. a Foreign Key constraint (rule)).
then :-
- The ON DELETE CASCADE says that if a parent is deleted then all the children of the parent are to be deleted down from the parent.
- The ON UPDATE is similar but cascades any change to the customer_id column in the customers table.
CREATE TABLE IF NOT EXISTS charges (
initialcharges REAL,
taxes REAL,
discount REAL,
advance REAL,
total REAL,
customer_id INTEGER REFERENCES customers(customer_id) ON DELETE CASCADE ON UPDATE CASCADE
);
Similar to services
Now say you then insert some (2) customers (noting that for the demo specific customer_id vales are specified rather than allowing them to be auto generated) using :-
INSERT OR IGNORE INTO customers VALUES
(10,'John','something','something','something')
,(20,'Jane','something','something','something')
;
and then use :-
SELECT *,rowid FROM customers;
Then :-
note that rowid is displayed as customer_id(1) as it now has customer_id as it's alias and that it exactly matches the value of the customer_id column.
Now we add some rows the the services table using:-
INSERT INTO services (service,subservice,customer_id) VALUES
('Exterior','something',10)
,('Interior','something',10)
,('Interior','something',20)
;
Note how the customer_id is a value from the customer_id column of the customers table and hence how you relate each services row to ONE customer.
using: -
SELECT *,rowid FROM services;
results in :-
again the rowid matches it's alias BUT both columns are both just a unique identifier of the row in the services table it has no meaning to the relationship between a service row and it's parent customer (hence why the rowid is of no use for what you want).
the important row, relationship wise, is the customer_id row which specifies the parent.
Similarly for the charges table :-
INSERT INTO charges (initialcharges,taxes,discount,advance,total,customer_id) VALUES
(10.50,0.50,1.5,0,11.50,10),
(105.00,05.00,1.5,0,115,20)
;
SELECT *,rowid FROM charges;
Now say you used-
SELECT customers.*,customers.rowid AS custid,' - ' AS ' ', services.*,services.rowid AS sid,' - ' AS ' ',charges.*,charges.rowid AS cid
FROM customers
JOIN services ON services.customer_id = customers.customer_id
JOIN charges ON charges.customer_id = customers.customer_id
;
then you get :-
If the name of John were changed to Fred using :-
UPDATE customers SET name = 'Fred' WHERE name = 'John';
Then as the John (now Fred) is accessed from the specific row it's change will be seen without any special processing in future queries e.g.
SELECT customers.*,customers.rowid AS custid,' - ' AS ' ', services.*,services.rowid AS sid,' - ' AS ' ',charges.*,charges.rowid AS cid
FROM customers
JOIN services ON services.customer_id = customers.customer_id
JOIN charges ON charges.customer_id = customers.customer_id
;
now results in :-
However, say the id for Jane were changed to 10000 using:-
UPDATE customers SET customer_id = 10000 WHERE customer_id = 20;
Then using the same query results in:-
i.e the ne value (10000) has automatically been applied to the children (not that you would likely change the customer_id often).
NOTE if you updated a child's column (if it did not violate the FK constraint) then that change IS NOT propagated to the parent. The parent would be switched.
Deletion works in a similar way, Delete the parent and the children will be deleted. Delete an child and just that child is child.
So with something like above, all you need to do is update whatever you need to update.
NOTE the above may or may not reflect actually what you want, it is rather a demonstration of the principle.

Cassandra Select Query using Collection Primary Key in Where Clause

I'm new to Cassandra and I created a table with a frozen collection as the primary key
cqlsh> create table rick_morty (id uuid, name text, adventure text, instigator frozen<set<text>>, PRIMARY KEY((instigator), adventure, name, id));
Now I want to query based on the primary key (instigator) for all of the values held in the collection. I have found that if I just wanted to query on 1 value, I can use CONTAINS 'contained_value', but I want to query on the entire collection.
I've been looking all over to figure out how to do this but I can't find the answer.
Doing something like
const query = 'SELECT name from rick_morty';
retrieves all results but I want to do something like...
const query = 'SELECT name from rick_morty where instigator = ["Rick", "Morty", "Beth"]';
to retrieve all list of names associated with that array of instigators.
Is this possible?? Did I just create my table in an improper way?
Is this possible??
Yes. See #8 here.
"Filter data on a column of a user-defined type. Create an index and then run a conditional query. In Cassandra 2.1.x, you need to list all components of the name column in the WHERE clause."
This should work:
SELECT name from rick_morty where instigator = { 'Rick', 'Morty', 'Beth'};
The following query should work,
SELECT name from rick_morty where instigator contains 'Rick' AND contains 'Morty';
But, This may not be an efficient/proper way to implement as Sets are meant to be used to store/get a set of data for a given primary key.
So, I would recommend you to re-design the data model by denormolise the query into a an additional table in case if this requirement is one of your primary use case.

SQLite regular table and table for fts

I have table news (id, news_id, news_title) and I creat FTS table:
CREATE VIRTUAL TABLE news_search USING fts4 (news_title, tokenize=porter);
I use trigger to keep table NEWS and news_search in sync:
CREATE TRIGGER IF NOT EXISTS insert_news_trigger
AFTER INSERT ON news
BEGIN
INSERT OR IGNORE INTO news_search (news_title) VALUES (NEW.news_title);
END;
Question: how to use search? When I do MATCH in news_search table it returns me only records from this table, but I need *news_id* from news table. May be I should add *news_id* column to news_search table?
What is the proper way to use fts in sqlite?
Read the documentation; FTS tables also have a rowid column (also called docid) that you can set explicitly to the same value as the corresponding key of the original table.
Assuming that news.id is the rowid (i.e., INTEGER PRIMARY KEY), you should change your trigger to also copy that ID value into the news_search table.
You can the use that to look up the original record:
SELECT *
FROM news
WHERE id IN (SELECT docid
FROM news_search
WHERE news_title MATCH '😸')

create table with constraints from another table in sqlite?

I want create table from another table with constraint?
I used this query "create table destination as select * from source;" fro table creation.
But its copy only the column name in table without column constraint.
There is a special table named sqlite_master, holding the full CREATE TABLE statement for each table (it's modified as appropriate during ALTER TABLE).
I would make my application retrieve that CREATE TABLE statement:
SELECT sql FROM sqlite_master WHERE type='table' AND name='source';
Then I would replace the table name right after CREATE TABLE tokens, and execute the result as a new sqlite query.
I don't think that it's possible to do in sqlite's pure SQL without extensions.

How can I move several columns from one table to a new one to-many table?

I'd like to refactor my database by splitting a single table into two. I'd like to moving a few existing columns to a new table. For instance, suppose I want to move the home_address and work_address fields in the below Employee table to a new Address table.
How can I accomplish this using sqlite?
Before:
Employee Table
employee_id (Primary)
name
home_address
home_city
work_address
work_city
After:
Employee Table
employee_id (Primary)
name
home_address_id
work_address_id
Address Table
address_id (Primary)
address
city
I prefer migrations to be simple and straightforward, without extra logic, etc. At least when you run them only once or so.
So, first check what is max(employee_id), below assumes that it less than 10000 (and it is integer).
create table employee_new(employee_id,name,home_address_id,work_address_id);
insert into employee_new select employee_id,name,employee_id,employee_id+10000 from employee;
create table address(address_id,address,city);
insert into address select employee_id,home_address,home_city from employee;
insert into address select employee_id+10000,work_address,work_city from employee;
alter table employee rename to employee_old;
alter table employee_new rename to employee;

Resources