SQLite n'est pas un jouet

Voici pourquoi SQLite est parfait pour votre travail quotidien. Peu importe que vous soyez dΓ©veloppeur, analyste, testeur, administrateur ou chef de produit.





Pour commencer, quelques faits connus:





  • SQLite est le systΓ¨me de gestion de base de donnΓ©es le plus utilisΓ© au monde et est inclus dans tous les systΓ¨mes d'exploitation courants.





  • Fonctionne sans serveur.





  • Pour les dΓ©veloppeurs, il est directement intΓ©grΓ© Γ  l'application.





  • Pour tout le monde - une console pratique (REPL) dans un seul fichier (sqlite3.exe sous Windows, sqlite3 sous Linux / macOS).





Console, import et export

La console est une fonctionnalité qui tue de SQLite: un outil d'analyse de données plus puissant qu'Excel, et beaucoup plus simple que n'importe quel pandas. Les données du CSV sont chargées avec une seule commande, la table est créée automatiquement:





> .import --csv city.csv city
> select count(*) from city;
1117
      
      



Les fonctionnalitΓ©s SQL de base sont prises en charge et la console affiche le rΓ©sultat dans une belle table. Il existe Γ©galement des fonctionnalitΓ©s SQL avancΓ©es, mais nous en parlerons ultΓ©rieurement.





select
  century || '- ' as dates,
  count(*) as city_count
from history
group by century
order by century desc;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  dates   β”‚ city_count β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 21-  β”‚ 1          β”‚
β”‚ 20-  β”‚ 263        β”‚
β”‚ 19-  β”‚ 189        β”‚
β”‚ 18-  β”‚ 191        β”‚
β”‚ 17-  β”‚ 137        β”‚
β”‚ 16-  β”‚ 79         β”‚
β”‚ 15-  β”‚ 39         β”‚
β”‚ 14-  β”‚ 38         β”‚
β”‚ 13-  β”‚ 27         β”‚
β”‚ 12-  β”‚ 44         β”‚
β”‚ 11-  β”‚ 8          β”‚
β”‚ 10-  β”‚ 6          β”‚
β”‚ 9-   β”‚ 4          β”‚
β”‚ 5-   β”‚ 1          β”‚
β”‚ 3-   β”‚ 1          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



Un tas de formats d'exportation de donnΓ©es: sql, csv, json, mΓͺme markdown et html. Tout se fait avec quelques commandes:





.mode json
.output city.json
select city, foundation_year, timezone from city limit 10;
.shell cat city.json
      
      



[{"city":"","foundation_year":1969,"timezone":"UTC+3"},
{"city":"","foundation_year":1857,"timezone":"UTC+3"},
{"city":"-","foundation_year":1830,"timezone":"UTC+7"},
{"city":"","foundation_year":1913,"timezone":"UTC+7"},
{"city":"","foundation_year":1730,"timezone":"UTC+7"},
{"city":"","foundation_year":1846,"timezone":"UTC+7"},
{"city":"","foundation_year":1709,"timezone":"UTC+7"},
{"city":"","foundation_year":1942,"timezone":"UTC+7"},
{"city":"","foundation_year":1748,"timezone":"UTC+7"},
{"city":"","foundation_year":1736,"timezone":"UTC+7"}]
      
      



Travailler avec JSON de manière native

Il n'y a rien de plus pratique que SQLite pour analyser et transformer JSON. Vous pouvez sΓ©lectionner des donnΓ©es directement Γ  partir du fichier, comme s'il s'agissait d'un tableau normal. Ou chargez-le dans une table et sΓ©lectionnez-le Γ  partir de lΓ  - comme vous prΓ©fΓ©rez.





select
  json_extract(value, '$.code') as code,
  json_extract(value, '$.name') as name,
  json_extract(value, '$.rate') as rate,
  json_extract(value, '$.default') as "default"
from
  json_each(readfile('currency.sample.json'))
;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ code β”‚       name        β”‚    rate    β”‚ default β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ AZN  β”‚             β”‚ 0.023107   β”‚ 0       β”‚
β”‚ BYR  β”‚   β”‚ 0.034966   β”‚ 0       β”‚
β”‚ EUR  β”‚               β”‚ 0.011138   β”‚ 0       β”‚
β”‚ GEL  β”‚     β”‚ 0.0344     β”‚ 0       β”‚
β”‚ KGS  β”‚      β”‚ 1.131738   β”‚ 0       β”‚
β”‚ KZT  β”‚              β”‚ 5.699857   β”‚ 0       β”‚
β”‚ RUR  β”‚              β”‚ 1.0        β”‚ 1       β”‚
β”‚ UAH  β”‚             β”‚ 0.380539   β”‚ 0       β”‚
β”‚ USD  β”‚            β”‚ 0.013601   β”‚ 0       β”‚
β”‚ UZS  β”‚       β”‚ 142.441417 β”‚ 0       β”‚
β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



Peu importe l'Γ©talement du JSON, vous pouvez choisir les attributs de n'importe quelle imbrication:





select
  json_extract(value, '$.id') as id,
  json_extract(value, '$.name') as name
from
  json_tree(readfile('industry.sample.json'))
where
  path like '$[%].industries'
;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   id   β”‚         name         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 7.538  β”‚ -   β”‚
β”‚ 7.539  β”‚ -        β”‚
β”‚ 7.540  β”‚          β”‚
β”‚ 9.399  β”‚        β”‚
β”‚ 9.400  β”‚    β”‚
β”‚ 9.401  β”‚   β”‚
β”‚ 43.641 β”‚                 β”‚
β”‚ 43.646 β”‚           β”‚
β”‚ 43.647 β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



OpΓ©rations CTE et set

, Common Table Expressions ( WITH



) , . ( parent_id



) β€”  WITH



. «»  .





with recursive tmp(id, name, level) as (
  select id, name, 1 as level
  from area
  where parent_id is null

  union all

  select
    area.id,
    tmp.name || ', ' || area.name as name,
    tmp.level + 1 as level
  from area
    join tmp on area.parent_id = tmp.id
)

select * from tmp;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”
β”‚  id  β”‚               name                  β”‚ level β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 113  β”‚                               β”‚ 1     β”‚
β”‚ 1    β”‚ ,                       β”‚ 2     β”‚
β”‚ 1586 β”‚ ,             β”‚ 2     β”‚
β”‚ 1588 β”‚ ,  ,    β”‚ 3     β”‚
β”‚ 78   β”‚ ,  ,    β”‚ 3     β”‚
β”‚ 212  β”‚ ,  ,  β”‚ 3     β”‚
β”‚ ...  β”‚ ...                                 β”‚ ...   β”‚
β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



? : UNION



, INTERSECT



, EXCEPT



.





select employer_id
from employer_area
where area_id = 1

except

select employer_id
from employer_area
where area_id = 2;
      
      



? β€” :





alter table vacancy
add column salary_net integer as (
  case when salary_gross = true then
    round(salary_from/1.13)
  else
    salary_from
  end
);
      
      



, :





select
  substr(name, 1, 40) as name,
  salary_net
from vacancy
where
  salary_currency = 'RUR'
  and salary_net is not null
limit 10;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   name                   β”‚ salary_net β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  - (Delphi)     β”‚ 40000      β”‚
β”‚   Scala / Java ( Senio β”‚ 60000      β”‚
β”‚ Java / Kotlin Developer                  β”‚ 150000     β”‚
β”‚   1                      β”‚ 150000     β”‚
β”‚  C#                           β”‚ 53097      β”‚
β”‚  1                           β”‚ 80000      β”‚
β”‚ Java -  (Middle, Senior)      β”‚ 100000     β”‚
β”‚  C#/ .NET                     β”‚ 70796      β”‚
β”‚  / QA engineer (  β”‚ 45000      β”‚
β”‚                                    β”‚ 17699      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



.

? : , , , . , . , ( ).





.load sqlite3-stats

select
  count(*) as book_count,
  cast(avg(num_pages) as integer) as mean,
  cast(median(num_pages) as integer) as median,
  mode(num_pages) as mode,
  percentile_90(num_pages) as p90,
  percentile_95(num_pages) as p95,
  percentile_99(num_pages) as p99
from books;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”
β”‚ book_count β”‚ mean β”‚ median β”‚ mode β”‚ p90 β”‚ p95 β”‚ p99  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€
β”‚ 1483       β”‚ 349  β”‚ 295    β”‚ 256  β”‚ 640 β”‚ 817 β”‚ 1199 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜
      
      



. SQLite - . , β€”  . .





, . , :





sqlite-plus (GitHub)





. . , :





with slots as (
  select
    num_pages/100 as slot,
    count(*) as book_count
  from books
  group by slot
),
max as (
  select max(book_count) as value
  from slots
)
select
  slot,
  book_count,
  printf('%.' || (book_count * 30 / max.value) || 'c', '*') as bar
from slots, max
order by slot;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ slot β”‚ book_count β”‚              bar               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 0    β”‚ 116        β”‚ *********                      β”‚
β”‚ 1    β”‚ 254        β”‚ ********************           β”‚
β”‚ 2    β”‚ 376        β”‚ ****************************** β”‚
β”‚ 3    β”‚ 285        β”‚ **********************         β”‚
β”‚ 4    β”‚ 184        β”‚ **************                 β”‚
β”‚ 5    β”‚ 90         β”‚ *******                        β”‚
β”‚ 6    β”‚ 54         β”‚ ****                           β”‚
β”‚ 7    β”‚ 41         β”‚ ***                            β”‚
β”‚ 8    β”‚ 31         β”‚ **                             β”‚
β”‚ 9    β”‚ 15         β”‚ *                              β”‚
β”‚ 10   β”‚ 11         β”‚ *                              β”‚
β”‚ 11   β”‚ 12         β”‚ *                              β”‚
β”‚ 12   β”‚ 2          β”‚ *                              β”‚
β”‚ 13   β”‚ 5          β”‚ *                              β”‚
β”‚ 14   β”‚ 3          β”‚ *                              β”‚
β”‚ 15   β”‚ 1          β”‚ *                              β”‚
β”‚ 17   β”‚ 1          β”‚ *                              β”‚
β”‚ 18   β”‚ 2          β”‚ *                              β”‚
β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



SQLite ( β€”  ). INSERT



240 . CSV ( ) β€”  2 .





.load sqlite3-vsv
create virtual table temp.blocks_csv using vsv(
    filename="ipblocks.csv",
    schema="create table x(network text, geoname_id integer, registered_country_geoname_id integer, represented_country_geoname_id integer, is_anonymous_proxy integer, is_satellite_provider integer, postal_code text, latitude real, longitude real, accuracy_radius integer)",
    columns=10,
    header=on,
    nulls=on
);
      
      



.timer on
insert into blocks
select * from blocks_csv;

Run Time: real 5.176 user 4.716420 sys 0.403866
      
      



select count(*) from blocks;
3386629

Run Time: real 0.095 user 0.021972 sys 0.063716
      
      



, SQLite , . . write-ahead log ( ) . β€” , .





SQLite . , sqlite.org SQLite , (~200 ). 700 , 95% .





,

, «» . .





SQLite : json json_extract()



:





create table currency(
  body text,
  code text as (json_extract(body, '$.code')),
  name text as (json_extract(body, '$.name'))
);

create index currency_code_idx on currency(code);

insert into currency
select value
from json_each(readfile('currency.sample.json'));
      
      



explain query plan
select name from currency where code = 'RUR';

QUERY PLAN
`--SEARCH TABLE currency USING INDEX currency_code_idx (code=?)
      
      



. WITH RECURSIVE



, :





simple-graph (GitHub)





:





create virtual table books_fts
using fts5(title, author, publisher);

insert into books_fts
select title, author, publisher from books;

select
  author,
  substr(title, 1, 30) as title,
  substr(publisher, 1, 10) as publisher
from books_fts
where books_fts match 'ann'
limit 5;
      
      



β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       author        β”‚             title              β”‚ publisher  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Ruby Ann Boxcar     β”‚ Ruby Ann's Down Home Trailer P β”‚ Citadel    β”‚
β”‚ Ruby Ann Boxcar     β”‚ Ruby Ann's Down Home Trailer P β”‚ Citadel    β”‚
β”‚ Lynne Ann DeSpelder β”‚ The Last Dance: Encountering D β”‚ McGraw-Hil β”‚
β”‚ Daniel Defoe        β”‚ Robinson Crusoe                β”‚ Ann Arbor  β”‚
β”‚ Ann Thwaite         β”‚ Waiting for the Party: The Lif β”‚ David R. G β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      
      



in-memory ? :





db = sqlite3.connect(":memory:")
      
      



:





db = sqlite3.connect("file::memory:?cache=shared")
      
      



( PostgreSQL). UPSERT



, UPDATE FROM



generate_series()



. R-Tree . , fuzzy- . SQLite «» .





, SQLite . , !





, SQLite β€” @sqliter








All Articles