Problem with alias in Sqliteman trying to make unique id´s - sql

I´m trying to translate this function from SQL server to Sqlite, how can i do it? I know it´s different but I just couldn´t. Any information will be awesome. Thanks
This is the code:
CREATE TABLE "user" (
"numId" INT IDENTITY(1,1) NOT NULL,
"prefix" VARCHAR(50) NOT NULL,
"id" AS ("prefix"+RIGHT('000000'+CAST(ID AS VARCHAR(7)),7))PERSISTED,
Thanks.

Normal SQL tables are called rowid tables, and have a unique integer as their primary key (A INTEGER PRIMARY KEY column aliases this rowid). So there's the IDENTITY bit taken care of.
While Sqlite 3.31 (In beta as of this writing) supports generated columns, until versions with that feature become widely available over the next few years, you can either create a VIEW that adds your custom prefix, or do it in each individual SELECT where it matters. Something like:
sqlite> CREATE TABLE actual_user(numId INTEGER PRIMARY KEY, prefix TEXT NOT NULL);
sqlite> CREATE VIEW user(numId, prefix, id) AS
...> SELECT numId, prefix, printf('%s%07d', prefix, numId) FROM actual_user;
sqlite> INSERT INTO actual_user(prefix) VALUES ('TEST'), ('TEST'), ('TESTX');
sqlite> SELECT * FROM user;
numId prefix id
---------- ---------- ------------
1 TEST TEST0000001
2 TEST TEST0000002
3 TESTX TESTX0000003
You might also emulate it with triggers for your table that updates the id value on insertion and update. This more closely mimics a persist (stored in SQLite lingo) generated column, while the view mimics a virtual column:
sqlite> CREATE TABLE user(numId INTEGER PRIMARY KEY, prefix TEXT NOT NULL, id TEXT);
sqlite> CREATE TRIGGER user_ai AFTER INSERT ON user
...> BEGIN UPDATE user SET id = printf('%s%07d', new.prefix, new.numId) WHERE numId = new.numId; END;
sqlite> CREATE TRIGGER user_au AFTER UPDATE OF numId, prefix ON user
...> BEGIN UPDATE user SET id = printf('%s%07d', new.prefix, new.numId) WHERE numId = new.numId; END;
sqlite> INSERT INTO user(prefix) VALUES ('TEST');
sqlite> SELECT * FROM user;
numId prefix id
---------- ---------- ------------
1 TEST TEST0000001
sqlite> UPDATE user SET prefix='APPLE' WHERE numId = 1;
sqlite> SELECT * FROM user;
numId prefix id
---------- ---------- ------------
1 APPLE APPLE0000001

Related

How to UPDATE or INSERT in PostgreSQL

I want to UPDATE or INSERT a column in PostgreSQL instead of doing INSERT or UPDATE using INSERT ... ON CONFLICT ... because there will be more updates than more inserts and also I have an auto incrementing id column that's defined using SERIAL so it increments the id column everytime it tries to INSERT or UPDATE and that's not what I want, I want the id column to increase only if it's an INSERT so that all ids would be in an order instead
The table is created like this
CREATE TABLE IF NOT EXISTS table_name (
id SERIAL PRIMARY KEY,
user_id varchar(30) NOT NULL,
item_name varchar(50) NOT NULL,
code_uses bigint NOT NULL,
UNIQUE(user_id, item_name)
)
And the query I used was
INSERT INTO table_name
VALUES (DEFAULT, 'some_random_id', 'some_random_name', 1)
ON CONFLICT (user_id, item_name)
DO UPDATE SET code_uses = table_name.code_uses + 1;
Thanks :)
Upserts in PostgreSQL do exactly what you described.
Consider this table and records
CREATE TABLE t (id SERIAL PRIMARY KEY, txt TEXT);
INSERT INTO t (txt) VALUES ('foo'),('bar');
SELECT * FROM t ORDER BY id;
id | txt
----+-----
1 | foo
2 | bar
(2 Zeilen)
Using upserts the id will only increment if a new record is inserted
INSERT INTO t VALUES (1,'foo updated'),(3,'new record')
ON CONFLICT (id) DO UPDATE SET txt = EXCLUDED.txt;
SELECT * FROM t ORDER BY id;
id | txt
----+-------------
1 | foo updated
2 | bar
3 | new record
(3 Zeilen)
EDIT (see coments): this is the expected behaviour of a serial column, since they're nothing but a fancy way to use sequences. Long story short: using upserts the gaps will be inevitable. If you're worried the value might become too big, use bigserial instead and let PostgreSQL do its job.
Related thread: serial in postgres is being increased even though I added on conflict do nothing

The last inserted rowid of a specific table in SQLite3

Is there a way to get the last inserted rowid of a specific table in SQLite3? There is a function last_insert_rowid which returns the rowid of the most recent successful INSERT into a rowid table or virtual table. However, I want to know whether there's such an method to get the last inserted rowid of a specific table.
The last inserted rowids of all tables are stored in the internal table sqlite_sequence, which you can query like any other table. Make sure your primary key ID has the attribute autoincrement, else it isn't listed there.
sqlite> create table Test1 (id integer primary key autoincrement, text string);
sqlite> create table Test2 (id integer primary key autoincrement, text string);
[...] -- Insert rows here
sqlite> select rowid from Test1;
id
----------
1
2
sqlite> select rowid from Test2;
id
----------
1
2
3
sqlite> select * from sqlite_sequence;
name seq
---------- ----------
Test1 2
Test2 3

How to add values in one table automatically when a condition is true

So, Here is the condition.
I have a User_tbl whose code is as follow
CREATE TABLE Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
user_type is either 0,1 or 2 .. If it is 0 then it is player , 1 is for coach and 2 is for audience.
Now, I want to create a new table which has lists of coach inside it . Whose schema will be
CREATE TABLE coach_tbl(
coach_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT
)
and what I need is that, when the entry which is placed in Users_tbl has user_type =1 then it should Trigger one other query which will create an entry in coach_tbl and fill the columns. It should happen dynamically .
The following TRIGGER would accomplish what you want :-
CREATE TRIGGER setup_coach
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coach_tbl (username, password) VALUES(new.username,new.password);
END
;
The following was used for testing the above :-
DROP TABLE IF EXISTS Users_tbl;
CREATE TABLE IF NOT EXISTS Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
DROP TABLE IF EXISTS coach_tbl;
CREATE TABLE IF NOT EXISTS coach_tbl(
coach_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT
);
CREATE TRIGGER setup_coach
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coach_tbl (username, password) VALUES(new.username,new.password);
END
;
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1);
The result being :-
Supplementary (aka Why not the above)
Storing the exact same values. i.e. duplicating them, is contrary to normalisation and could lead to issues. e.g. if (using the above) "Bert"'s name or "password" changed you'd have to change it in two places. As it stands there is no need to duplicate this data as it would be easily available
For example, if you wanted to list the coaches you could use :-
SELECT username FROM coach_tbl;
Using the following, though, returns exactly the same but without the additional table :-
SELECT username FROM Users_tbl WHERE user_type = 1;
Supposing you had coach specific information say for example the number of times coaching then you could have an additional table such as :-
CREATE TABLE IF NOT EXISTS coaching_information
(
user_id_reference INTEGER REFERENCES Users_tbl(id),
number_of_times_coaching INTEGER DEFAULT 0
)
;
Along with a TRIGGER to automatically add default coaching information :-
CREATE TRIGGER autoadd_coaching_information_entry
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coaching_information
(user_id_reference)
VALUES (new.id)
;
END
;
Note! no need to set the number_of_times_coaching column as it will default to 0.
Assuming that all TABLES have been emptied then using (again):-
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1);
results in :-
2 refers to Bert, 4 to Alan
You could then list all coaches who have not coached (chosen for laziness of not having to update coaching inforamtion) :-
SELECT 'Coach '||username||' is up for a coaching experience.' AS coaching_needed
FROM coaching_information
JOIN Users_tbl ON Users_tbl.id = coaching_information.user_id_reference
WHERE coaching_information.number_of_times_coaching < 1
The result would be :-
Say Bert changed name to Charles e.g. using UPDATE Users_tbl SET username = 'Charles' WHERE username = 'Bert';
Then just with the 1 change the results from the above query would be :-
The full SQL used for testing the above was :-
DROP TABLE IF EXISTS coach_tbl;
DROP TABLE IF EXISTS Users_tbl;
CREATE TABLE IF NOT EXISTS Users_tbl (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username TEXT,
password TEXT,
user_type INT
);
DROP TRIGGER IF EXISTS setup_coach; -- get rid of defunct TRIGGER
CREATE TABLE IF NOT EXISTS coaching_information
(
user_id_reference INTEGER REFERENCES Users_tbl(id) ON DELETE CASCADE,
-- Note ON DELETE CASCADE will automatically delete a coach should
-- the coach's User_tbl entry be deleted i.e. the deletion is propoagted
-- to the children of the parent.
-- (could also use ON UPDATE CASCADE but unlikely to change the underlying id)
number_of_times_coaching INTEGER DEFAULT 0
)
;
DROP TRIGGER IF EXISTS autoadd_coaching_information_entry;
CREATE TRIGGER autoadd_coaching_information_entry
AFTER INSERT ON Users_tbl
WHEN new.user_type = 1
BEGIN
INSERT INTO coaching_information
(user_id_reference)
VALUES (new.id)
;
END
;
INSERT INTO Users_tbl (username, password,user_type)
VALUES
('Fred','fred1234',0),
('Bert','bert1234',1),
('Harold','harold1234',0),
('Alan','alan1234',1)
;
--
-- Note! oncommmenting this will change Bert's name to Charles
--UPDATE Users_tbl SET username = 'Charles' WHERE username = 'Bert';
--
SELECT 'Coach '||username||' is up for a coaching experience.' AS coaching_needed
FROM coaching_information
JOIN Users_tbl ON Users_tbl.id = coaching_information.user_id_reference
WHERE coaching_information.number_of_times_coaching < 1

Storing a database reference within the database

I want to be able to label the database with a single value, i.e its name, from within the database instead of my application, since it will always be one ID per database. For example, something like this:
DATABASE_A.sql
-- Database Name Table
CREATE TABLE database (
name VARCHAR(10) NOT NULL UNIQUE,
);
CREATE TABLE item (
id SERIAL PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE,
);
Insert Into database (name) values ('A');
DATABASE_B.sql
-- Database Name Table
CREATE TABLE database (
name VARCHAR(10) NOT NULL UNIQUE,
);
CREATE TABLE item (
id SERIAL PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE,
);
Insert Into database (name) values ('B');
This is because when they are combined and stored on a SOLR search server their ID is a combination of their database name and their item ID, such as this:
SOLR ITEM ID's
A1
A2
A3
B1
Is it ok to have a single table to define the prefix so that when I do the look up from my SQL website to SOLR I can just do the following query:
database (name) + item (id) = SolrID
I'd be more inclined to build a procedure in each database that contained the database ID, for example:
CREATE OR REPLACE FUNCTION solrid(IN local_id INTEGER, OUT result TEXT) AS $$
DECLARE
database_id TEXT := 'A';
BEGIN
result := database_id || local_id::TEXT;
END;
$$ LANGUAGE PLPGSQL;
Then you could write your select statement like:
SELECT solrid(id), name FROM item;
which seems to be a cleaner solution.

SQLPlus AUTO_INCREMENT Error

When I try and run the following command in SQLPlus:
CREATE TABLE Hotel
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
hotelName VARCHAR(20) NOT NULL,
city VARCHAR(50) NOT NULL,
CONSTRAINT hotelNo_pk PRIMARY KEY (hotelNo));
I get the following error:
(hotelNo NUMBER(4) NOT NULL AUTO_INCREMENT,
*
ERROR at line 2:
ORA-00907: missing right parenthesis
What am I doing wrong?
Many will gripe about this not being a standard feature in Oracle, but when it’s as easy as two more commands after your CREATE TABLE command I can’t see any good reason to use fancy SQL on every insert.
First let’s create a simple table to play with.
SQL> CREATE TABLE test
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
Table created.
Now we’ll assume we want ID to be an auto increment field. First we need a sequence to grab values from.
SQL> CREATE SEQUENCE test_sequence
START WITH 1
INCREMENT BY 1;
Sequence created.
Now we can use that sequence in a BEFORE INSERT trigger on the table.
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON test
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT test_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
SQL> INSERT INTO test (name) VALUES ('Jon');
1 row created.
SQL> INSERT INTO test (name) VALUES (’Bork’);
1 row created.
SQL> INSERT INTO test (name) VALUES (’Matt’);
1 row created.
SQL> SELECT * FROM test;
ID NAME
———- ——————————
1 Jon
2 Bork
3 Matt
Oracle has no auto_increment, you need to use sequences.
Or - starting with Oracle 12.1 - you can simply have:
CREATE TABLE employee
(
id NUMBER GENERATED by default on null as IDENTITY
....
)