SQLite: How to insert with a new rowid after having deleted one? - sqlite

Suppose my table is,
CREATE TABLE bookmark (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name STRING(64)
);
I have inserted three rows in this table, like this:
Id | Name
1 | Bookmark 1
2 | Bookmark 2
3 | Bookmark 3
Now If I delete the row 3, so I get this:
Id | Name
1 | Bookmark 1
2 | Bookmark 2
And now I insert a new row with name Bookmark 4, I get this:
Id | Name
1 | Bookmark 1
2 | Bookmark 2
3 | Bookmark 4
Should not I be expecting the following?
Id | Name
1 | Bookmark 1
2 | Bookmark 2
4 | Bookmark 4
Anyone knows how to do this?
Notice: It is not a SQLite behavior but more of a SQLAlchemy problem. As #CL. points out here, it REALLY DOES what I wanted.

Sorry folks, finally I've found out it is caused by SQLAlchemy 1.1.13, it is not setting AUTOINCREMENT field for SQLite even we have specified like following,
db = SQLAlchemy()
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
As I use Flask, when specify,
app.config['SQLALCHEMY_ECHO'] = True
The log shows that AUTOINCREMENT is actually not set.
After some digging, to do it for SQLite, in SQLAlchemy 1.1.13 (source),
class Bookmark(db.Model):
__tablename__ = "bookmark"
__table_args__ = {'sqlite_autoincrement': True}
For SQLAlchemy 1.2, the following may work (not tested),
id = db.Column(db.Integer, primary_key=True, sqlite_autoincrement=True)

Related

Interactive Grid:Process with PL/SQL only that isn't based off a table

Env: Oracle APEX v5.1 with Oracle 12c Release 2
Firstly, I have created an Interactive Grid that isn't based off an underlying table as I will process this manually using PL/SQL.
I have been using the following as a guide:
https://apex.oracle.com/pls/apex/germancommunities/apexcommunity/tipp/6361/index-en.html
I basically have the following query:
select
level as id,
level as grid_row,
null as product,
null as product_item
from dual connect by level <= 1
Concentrating on just the product and product_item columns where the product_item column will be a readonly column and only the product number can be entered, I would like to achieve the following:
Product Product Item
---------- -------------
123456 123456-1
123456 123456-2
556677 556677-1
654321 654321-1
654321 654321-2
654321 654321-3
123456 123456-3
From the above, as the user types in the Product and then tabs out of the field, I would like a DA to fire that will add the sequence of "-1" to the end of that product number. Then is the user then adds another row within the IG and enters the same product number, I then want it to append "-2" to the end of it.
Only when the product changes number, I need the sequence to reset to "-1" for that new product as per 556677 and so forth.
Other scenarios that should also be taken into consideration are as follows:
From above IG, the user entered 123456 again but this should calculate that the next sequence for 123456 is "-3"
The same needs to be catered for, when a Product is removed from the IG but to always look at the max sequence number for that product.
I was thinking of possibly using APEX_COLLECTIONS as a means of storing what is currently in the grid, since no changes have been committed to the database.
Assuming you have a collection of product values (in this case, I am using the built-in SYS.ODCINUMBERLIST which is a VARRAY data type) then the SQL for your output would be:
SELECT id,
id AS grid_row,
product,
product || '-' || ROW_NUMBER() OVER ( PARTITION BY product ORDER BY id )
AS product_item
FROM (
SELECT ROWNUM AS id,
COLUMN_VALUE AS product
FROM TABLE(
SYS.ODCINUMBERLIST(
123456,
123456,
556677,
654321,
654321,
654321,
123456
)
)
)
ORDER BY id
Output:
ID | GRID_ROW | PRODUCT | PRODUCT_ITEM
-: | -------: | ------: | :-----------
1 | 1 | 123456 | 123456-1
2 | 2 | 123456 | 123456-2
3 | 3 | 556677 | 556677-1
4 | 4 | 654321 | 654321-1
5 | 5 | 654321 | 654321-2
6 | 6 | 654321 | 654321-3
7 | 7 | 123456 | 123456-3
db<>fiddle here
As you mentioned, the data you enter is not saved into the DB whilst you are inserting your products, so it is not in fact stored anywhere.
So you cannot go check if that value already exists and enter a -2 or other.
Some things to consider would be to maybe save the values into a temp table so you can then have a function go check how many product_item like 123456-% are in there and use that number +1 as your new product_item.
Or you could go the even harder way and do it all with javascript. For this you will need to somehow get all records in the IG, go through them all and see how many occurences of 123456 you have and then insert 123456-(no of occurences + 1).

Unique Index on two columns and vice versa

I have the following table in postgres 9.5:
CREATE TABLE public.test
(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer,
id2 integer,
CONSTRAINT test_pkey PRIMARY KEY (id)
);
I want to add restrictions on both columns which only allows recordsets where
the new recordset (id1,id2) is not present and
the new recordset (id1,id2) is not present as (id2,id1) and
id1 and id2 of new recordset are not equal
It should lool like this:
id | id1 | id2
---------------
1 | 1 | 1 <-- invalid (violates restriction 3.)
2 | 1 | 2 <-- valid
3 | 1 | 2 <-- invalid (violates restriction 1.)
4 | 2 | 1 <-- invalid (violates restriction 2.)
5 | 3 | 1 <-- valid
6 | 3 | 2 <-- valid
For restriction 1, I have added:
ALTER TABLE test ADD CONSTRAINT test_id1_id2_unique UNIQUE(id1, id2);
But how to add constraints for 2. and 3.?
Final solution with help of a_horse_with_no_name:
CREATE TABLE public.test(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer NOT NULL,
id2 integer NOT NULL,
CONSTRAINT test_pkey PRIMARY KEY (id),
CONSTRAINT test_check CHECK (id1 <> id2)
);
CREATE UNIQUE INDEX test_id1_id2_unique
ON public.test
USING btree
((LEAST(id1, id2)), (GREATEST(id1, id2)));
You can create a unique index to cover both 1. and 2.
create unique index on test ( least(id1,id2), greatest(id1,id2) );
For 3. you need a check constraint:
CREATE TABLE public.test
(
id bigint NOT NULL DEFAULT nextval('test_id_seq'::regclass),
id1 integer,
id2 integer,
constraint check_not_equal check (id1 is distinct from id2),
CONSTRAINT test_pkey PRIMARY KEY (id)
);
You probably want both ids to be NOT NULL as well. In that case you could also use check (id1 <> id2)

SQLite: delete all records from table specified in another table

Having tables like this
mytab deltab
--------- --------
id | name id | name
1 | Ann 2 | Bob
2 | Bob 3 | Cindy
3 | Cindy
4 | Dave
I'd like to perform query which deletes all records in mytab specified in deltab, so only Ann and Dave would be left in mytab.
While there is MySQL multiple-table delete syntax, looks like there is no such thing in SQLite delete syntax.
I am considering REPLACE syntax with select-stmt and mark the rows which will be deleted (like set these names to NULL) in DELETE query after. I wonder if there is more effective way?
Try this query
Delete from mytab where id in (select id from deltab);
Try this:
DELETE FROM mytab
WHERE EXISTS (SELECT *
FROM deltab
WHERE deltab.ID = mytab.ID)

How to get ID from table A to table B in trigger?

I have two tables, A & B:
TABLE A
id | name
TABLE B
id | name | fk_idA
I want to create trigger AFTER INSERT in TABLE B which updates fk_idA appropriate with the newest id from table A.
An example:
TABLE A
id | name
1 | Andrew
2 | David
TABLE B
id | name | fk_idA
1 | Photo1 | 2
If the ID column is autoincrementing, the latest is the largest one, i.e., the one returned by MAX:
CREATE TRIGGER DefaultAIsLatest
AFTER INSERT ON TableB
FOR EACH ROW
WHEN NEW.fk_idA IS NULL
BEGIN
UPDATE TableB
SET fk_idA = (SELECT MAX(id)
FROM TableA)
WHERE id = NEW.id;
END;

selecting a row based on a number of column values in SQLite

I have a table with this structure:
id | IDs | Name | Type
1 | 10 | A | 1
2 | 11 | B | 1
3 | 12 | C | 2
4 | 13 | D | 3
except id nothing else is a FOREIGN or PRIMARY KEY. I want to select a row based on it's column values that are not PRIMARY KEY. I have tried the following syntax but it yields no results.
SELECT * FROM MyTable WHERE Name = 'A', Type = 1;
what am I doing wrong? What is exactly returned by a SELECT statement? I'm totally new to Data Base and I'm currently experimenting and trying to learn it. so far my search has not yield any results regarding this case.
Use and to add multiple conditions to your query
SELECT *
FROM MyTable
WHERE Name = 'A'
AND Type = 1;

Resources