How to emulate REPEAT() in SQLite
My answer combines Shiplu Mokaddim's "printf character substitution repetition" with the "replace" of Steve Broberg and Lukas Eder:
sqlite> SELECT replace(printf('%.' || 5 || 'c', '/'),'/','My string ');
My string My string My string My string My string
It's also easy to derive the number of repetitions from table data. Here's an example using a common table expression:
sqlite> WITH cte(string, reps) AS
..> (SELECT * FROM (values ('alpha ', 1),('bravo ', 5),('charlie ', 3) ) )
..> SELECT *, replace(printf('%.' || reps || 'c', '/'), '/', string) FROM cte;
alpha 1 alpha
bravo 5 bravo bravo bravo bravo bravo
charlie 3 charlie charlie charlie
How to emulate LPAD/RPAD with SQLite
A simpler version of @user610650's solution, using hex() instead of quote(), and works with string padding in addition to char padding:
X = padToLength
Y = padString
Z = expression
select
Z ||
substr(
replace(
hex(zeroblob(X)),
'00',
Y
),
1,
X - length(Z)
);
Sqlite column with repetitive values
The question is very similar to Add data to many-to-many relation with one SQL command, but it also discusses further aspect - automatic clean-up of unused entities.
Is there a way to let SQLite do everything automatically? ... (without having to maintain anything ourselves)
No. You basically want to insert rows in the base table and referenced table if it doesn't exist yet, while specifying the reference by value rather than its surrogate key. That in fact isn't a straightforward task in other RDBMSes as well. Some of them support:
- Stored procedures
- Multitable inserts
- OUTPUT clause
- RETURNING clause
- Writable (updatable) views
INSTEAD OF
triggers on views
From the above list SQLite only supports INSTEAD OF
triggers. Here's how it applies to your use case (I have adopted table words
from your db<>fiddle mentioned in comments under the question and renamed its column a
to value
):
PRAGMA foreign_keys = ON;
CREATE TABLE words(
id INTEGER PRIMARY KEY,
value TEXT
);
CREATE UNIQUE INDEX unique_words_value ON words(value);
CREATE TABLE data(
id INTEGER PRIMARY KEY,
word_id INTEGER NOT NULL,
FOREIGN KEY (word_id) REFERENCES words(id)
);
CREATE VIEW data_view AS
SELECT d.id, w.value FROM data AS d INNER JOIN words AS w on w.id = d.word_id;
CREATE TRIGGER data_view_insert INSTEAD OF INSERT ON data_view
BEGIN
INSERT OR IGNORE INTO words(value) VALUES (NEW.value);
INSERT OR IGNORE INTO data(word_id) VALUES(
(SELECT id FROM words WHERE value = NEW.value)
);
END;
INSERT INTO data_view (value) VALUES
('random1'),
('random2'),
('random3'),
('random1'),
('random3'),
('random4');
The INSERT
statement produced this content of table words
:
id | value |
---|---|
1 | random1 |
2 | random2 |
3 | random3 |
4 | random4 |
Using GLOB to match each character in an SQLite TEXT field
In SQLite there is a trick to emulate a function like MySql's REPEAT()
which returns a string repeated n times.
So by:
REPLACE(HEX(ZEROBLOB(8)), '00', '[A-HJ-NPR-Z0-9]')
you get the string '[A-HJ-NPR-Z0-9]'
repeated 8 times:
[A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9][A-HJ-NPR-Z0-9]
You can use this trick to construct (by concatenations) the string that you need after GLOB
in your CHECK
constraint:
CHECK(myfield GLOB
REPLACE(HEX(ZEROBLOB(8)), '00', '[A-HJ-NPR-Z0-9]') ||
'[X0-9]' ||
REPLACE(HEX(ZEROBLOB(8)), '00', '[A-HJ-NPR-Z0-9]')
)
See a simplified demo.
Is there any string operators like the POSITION() method of MySQL available in SQLite3?
From Instr, Locate or Splite it seems no, but you can implement your own
I think you will have to write your
own user defined function to do this.
The SQL standard defines a POSITION()
function that returns the position of
one string within another, but sqlite
doesn't implement it. It should be
fairly simple to provide your own
function to do this. You can look at
the standard functions in func.c for
some examples of using the custom
function API routines (the same
routines are used to define all the
standard functions; sum, round,
substr, etc.).
Oracle INSTR replacement in SQLite
SQL
CASE WHEN position = 0
THEN INSTR(string, substring)
WHEN position > 0
THEN INSTR(SUBSTR(string, position), substring) + position - 1
WHEN position < 0
THEN LENGTH(RTRIM(REPLACE(string,
substring,
REPLACE(HEX(ZEROBLOB(LENGTH(substring))),
'00',
'¬')),
string)) - LENGTH(substring) + 1
END
It assumes the ¬
character won't be part of the search string (but in the unlikely event this assumption is false could of course be changed to a different rarely used character).
SQLFiddle Demo
Some worked examples here: http://sqlfiddle.com/#!5/7e40f9/5
Credits
- The positive
position
method was adapted from Tim Biegeleisen's answer. (But a zero value needs to be handled separately). - The negative
position
method used the method described in this question as a starting point. - The creation of a string consisting of a character repeated n times was taken from this simplified answer.
Related Topics
Find Min and Max for Subsets of Consecutive Rows - Gaps and Islands
SQL Server Count Number of Distinct Values in Each Column of a Table
Postgres Won't Accept Table Alias Before Column Name
How to Select First N Rows from a Table in T-Sql
Call a Stored Procedure in SQL Cte
How to Get the Nth Row in a SQL Server Table
SQL Server Audit Logout Creates Huge Number of Reads
SQL Query Where Date = Today Minus 7 Days
Calculate the Last Day of the Prior Quarter
SQL - Safely Downcast Bigint to Int
Postgresql - Order by an Array
How to Improve This Mailing Address SQL Server Select Statement
Mod Negative Numbers in SQL Just Like Excel
SQL Server: Self-Reference Fk, Trigger Instead of on Delete Cascade