Go тілі: нөлден өз блогыңызға дейін 27-сабақ (барлығы 50)
SQL: алғашқы кесте, INSERT және SELECT
Go курсының жиырма жетінші сабағы. Мақалалар ақыры қайта қосудан аман қалады. Курста неге Postgres емес, SQLite, кестені қалай жасап, оған жолды қалай салу керек: RETURNING-пен insert, WHERE мен ORDER BY-мен select, WHERE ұмытылған update және = null мен is null айырмасы.
Не үшін керек
Блог мақалаларды тілімде ұстайды. Бағдарламаны қайта қостыңыз — мақала жоқ. Оқырман форма арқылы жазғанның бәрі алғашқы Ctrl+C-ге дейін ғана өмір сүреді.
Дерекқор — деректің іске қосулар арасында жататын орны, ал SQL — онымен сөйлесетін тіл. Бүгін тек SQL, Go-да бір жол да жоқ: Go дерекқорға келесі сабақта қосылады, ал онда не жіберетініңізді түсініп барған дұрыс.
Бірден ескерту. Бұл — SQL курсы емес, бұл блог жұмыс істейтін ең аз мөлшер. Нағыз SQL бұдан әлдеқайда кең, әрі оны бастапқы дереккөздерден үйрену керек: SQLite құжаттамасы және PostgreSQL оқулығы. Мұнда дәл алты пәрмен мен екі тұзақ аламыз.
Екі сөзді бірден келісіп алайық. Бұл сабақта жол — кестенің жолы, яғни бір мақаланың жазбасы, ал сұраныс — дерекқорға жіберілген SQL. Веб бөліміндегі HTTP-сұраныспен де, кодтың жолымен де шатастырмаңыз: сөз бір, мағынасы басқа.
Неге Postgres емес, SQLite
Олардың айырмасы біреуі «оқуға арналған», екіншісі «нағыз» болғанында емес. Айырма — құрылысында.
Postgres — сервер-бағдарлама. Ол сіздің бағдарламаңыздан бөлек, үнемі жұмыс істейді, портты тыңдайды, өз пайдаланушылары мен олардың құпия сөздерін біледі. Сіздің бағдарламаңыз оған желі арқылы қосылады — ол желі бір компьютерден шықпаса да. Дәл қазір менің машинамда PostgreSQLке он бір қосылым ашық, әрі мен осы мәтінді жазып отырғанда ол соларға қызмет көрсетіп тұр.
SQLite — сіздің бағдарламаңыздың ішіндегі кітапхана. Ешқандай сервер жоқ. Порт жоқ, пайдаланушы жоқ, іске қосатын қызмет жоқ. Дискідегі файл бар, әрі оны оқи және жаза алатын код бар. «Дерекқорға қосылу» мұнда «файлды ашу» дегенді білдіреді.
Қалғанының бәрі осыдан шығады. Орнату: sqlite3 Mac-та тұрып қойған, Linux-та бір пәрменмен қойылады; PostgreSQLке қызмет, рөл, құпия сөз және role "..." does not exist хабарламасымен алғашқы кездесу керек. Сақтық көшірме: файлды көшіру. Блогты басқа компьютерге көшіру: файлды көшіру. Бәрін өшіріп қайта бастау: файлды өшіру.
Бұл ойыншық дерекқор емес
SQLite туралы ол кішкентай әрі байыпсыз нәрсе деп ойлау оңай. Шындығында бұл, бәлкім, әлемдегі ең көп таралған дерекқор — әзірлеушілері солай жазады: «Android-тегі әрбір құрылғы», «әрбір iPhone», әрі олардың бағалауынша әлемде триллионнан астам тірі SQLite файлы бар.
Ол дәл қазір сіздің телефоныңызда жатыр, әрі бір данада емес: байланыстар, хабарламалар, браузер тарихы, қосымшалардың баптауы — бұлардың бәрі әдетте SQLite файлдары. Оны Apple, Google, Microsoft, Mozilla пайдаланады; ол Airbus ұшақтарында және Bosch автомобиль электроникасында тұр — бұл олардың өз тізімі.
Сондықтан сіз макетте үйреніп жатқан жоқсыз. Сіз қалтаңызда жүрген қозғалтқышта үйреніп жатырсыз.
Postgres не істей алады, ал SQLite — жоқ
Шекараны түсінуіңіз үшін адал тізім.
Бір мезгілде бірнеше жазушы. SQLite-та дерекқорға бір-бірлеп қана жазуға болады. Тексеру оңай: екі қосылым ашамыз, екеуінде де жазуды бастаймыз — екіншісі database is locked алады. Өзіңіз жалғыз жазатын блог үшін бұның маңызы жоқ; жүз кассирі бар дүкен үшін — бар.
Құқығы бар желілік қолжетім. Постгреске әртүрлі машинадан бес бағдарлама қосылады, әрқайсысының өз құпия сөзі мен рұқсаты бар. SQLite-қа файлға қолжетімі бар адам «қосылады».
Тип пен мүмкіндік көбірек. Күндер, массивтер, индексі бар JSON, толық мәтіндік іздеу — PostgreSQLте бұлардың бәрі бай. SQLite-та тіпті логикалық тип жоқ, оған қазір көз жеткізесіз.
Курс сіздің компьютеріңізде жұмыс істейтін блог уәде етеді, әрі осы уәде үшін SQLite жақсырақ келеді. Сіз сонда да SQLite емес, SQL үйренесіз: схема, кілттер, join, транзакциялар Postgres-ке қайта үйренусіз көшеді. Shanraq.org өзі Postgres-те жұмыс істейді — модуль соңында көшкенде не өзгеретінін талдаймыз.
Бірден тұтас
sqlite3 macOS-та тұрып қойған. Ubuntu-да — sudo apt install sqlite3, Windows-та — sqlite.org сайтынан бір файл.
Қалта жасаңыз, онда дерекқор ашыңыз — файл өзі жасалады:
sqlite3 blog.db
Кестелер оқылатын болуы үшін екі жол баптау, әрі үшіншісі — ол туралы сабақ соңында бөлек әңгіме болады:
.mode box
.headers on
pragma foreign_keys = on;
Үшінші жолды sqlite3-ке әр кіргенде қайталауға тура келеді. Неге екенін өшіруге жеткенде өзіңіз көресіз.
Және схема — әзірге бір кесте:
create table articles (
id integer primary key,
slug text not null unique,
title text not null,
words integer not null default 0,
published integer not null default 0,
created text not null default (datetime('now'))
) strict;
Шығу — .quit. Жазғаныңыздың бәрі қасындағы blog.db файлында қалды.
Талдау
Кесте — бір рет жазылған тип
create table деректің пішінін Go-дағы struct мәннің пішінін сипаттағандай сипаттайды. Айырмасы — бұл пішіннің сақталуын сіз емес, дерекқор қадағалайды.
not null — баған бос бола алмайды. slug-тегі unique — бір мекенжайлы екі мақала болмайды, әрі мұны кодта тексерудің қажеті жоқ: сондай екіншісін салу әрекеті қатемен бітеді. default 0 — мән жіберілмесе, нөл болады.
primary key — жолды қалғандарынан ерекшелейтін нәрсе. SQLite-та integer primary key оның үстіне «нөмірін өзі қойсын» дегенді білдіреді: бірінші жолға 1, келесісіне 2 тиеді.
SQLite бөтен мысалдардан ерекшеленетін екі жер.
Соңындағы strict — типтерді сақтау талабы. Онсыз SQLite integer бағанына 'abc' салуға келіседі, әрі сіз бұл туралы кеш білесіз. strict дегенді әрқашан жазыңыз.
SQLite-та логикалық тип жоқ. published integer 0 мен 1 сақтайды, ал сұраныстағы true мен false сөздері — сол бірлік пен сол нөлдің ыңғайлы жазылуы ғана.
insert және returning
insert into articles (slug, title, words, published)
values ('dala', 'Дала туралы', 400, true)
returning id, slug, created;
┌────┬──────┬─────────────────────┐
│ id │ slug │ created │
├────┼──────┼─────────────────────┤
│ 1 │ dala │ 2026-09-06 07:15:52 │
└────┴──────┴─────────────────────┘
Біз id мен created бермедік — оларды дерекқор қойды. returning не шыққанын сол пәрменмен қайтарады: онсыз салып, содан кейін бөлек сұраныспен «қандай id бердің» деп сұрауға тура келер еді.
Бірнеше жолды бір пәрменмен салады:
insert into articles (slug, title, words, published) values
('shanyraq', 'Шаңырақ деген не', 1000, true),
('salem', 'Сәлем, әлем', 150, true),
('draft', 'Жоба', 20, false);
select: нені, қайдан және қандай ретпен алу
select id, slug, title, words, published from articles order by id;
┌────┬──────────┬──────────────────┬───────┬───────────┐
│ id │ slug │ title │ words │ published │
├────┼──────────┼──────────────────┼───────┼───────────┤
│ 1 │ dala │ Дала туралы │ 400 │ 1 │
│ 2 │ shanyraq │ Шаңырақ деген не │ 1000 │ 1 │
│ 3 │ salem │ Сәлем, әлем │ 150 │ 1 │
│ 4 │ draft │ Жоба │ 20 │ 0 │
└────┴──────────┴──────────────────┴───────┴───────────┘
order by жоқта жолдардың реті анықталмаған. Ол салу ретімен сәйкес келуі мүмкін, ал алғашқы өшіруден кейін сәйкес келмей қалады. Рет керек болса — оны анық сұраңыз.
Әрі қарай блог сұраныстарының көбі құралатын үш сөз:
select slug, title, words
from articles
where published = 1 and words > 100
order by words desc
limit 2;
┌──────────┬──────────────────┬───────┐
│ slug │ title │ words │
├──────────┼──────────────────┼───────┤
│ shanyraq │ Шаңырақ деген не │ 1000 │
│ dala │ Дала туралы │ 400 │
└──────────┴──────────────────┴───────┘
where жолдарды сүзеді, order by ... desc кемуі бойынша сұрыптайды, limit қияды. Басты бет дәл осыдан жиналады: соңғы он жарияланған мақала.
update: where — әшекей емес
update articles set words = 300, published = 1 where slug = 'draft';
select changes() as өзгертілді;
┌────────────┐
│ өзгертілді │
├────────────┤
│ 1 │
└────────────┘
changes() қанша жол өзгергенін айтады. Біреу — қалағанымыздай.
Ал енді осы бөлім не үшін жазылғаны. where дегенді алып тастаңыз:
begin;
update articles set published = 0;
select changes() as өзгертілді;
rollback;
┌────────────┐
│ өзгертілді │
├────────────┤
│ 4 │
└────────────┘
Төртеу. where жоқ update бүкіл кестені өзгертеді, әрі ешқандай ескерту болмайды.
Мұнда бізді басындағы begin мен соңындағы rollback сөзі құтқарды: өзгерістер болмағандай кері қайтты.
select count(*) as жарияланған from articles where published = 1;
┌─────────────┐
│ жарияланған │
├─────────────┤
│ 4 │
└─────────────┘
Транзакциялар — бөлек сабақтың тақырыбы, ал әзірге осы екі сөзді қауіпсіздік белбеуі ретінде есте сақтаңыз: update не delete дегенге күмәндансаңыз — begin-ге ораңыз да, commit жазар алдында санға қараңыз.
Елестетіп көріңіз. Кесер алдында қай аяқты операциялайтынын тағы бір рет оқитын хирург. Есінде жоқ болғандықтан емес, қатенің құны симметриялы емес болғандықтан.
null — мән емес, оның жоқтығы
Бәрінде толтырылмаған баған қосайық:
alter table articles add column cover text;
update articles set cover = '/static/dala.svg' where slug = 'dala';
Енді дерекқордан мұқабасыз мақалаларды сұрайық — әдет қалай айтса, солай. Әрі бос жауап көрінуі үшін артынша екінші сұрақ:
select slug from articles where cover = null;
select count(*) as барлығы from articles;
┌─────────┐
│ барлығы │
├─────────┤
│ 4 │
└─────────┘
Бірінші сұраныс ештеңе баспады: жол да, қате де, ескерту де жоқ. Екіншісі бірден мақала төртеу екенін, ал мұқаба олардың үшеуінде жоқ екенін айтты.
Себебі null — мән емес, «мұнда ештеңе жоқ» деген белгі. Онымен салыстыруға болмайды: cover = null «белгісіз белгісізге тең бе» деп сұрайды, ал бұған жауап «иә» де, «жоқ» та емес, «белгісіз». Жол жауапқа тек «иә» бойынша түседі.
Дұрысы былай:
select slug from articles where cover is null order by id;
┌──────────┐
│ slug │
├──────────┤
│ shanyraq │
│ salem │
│ draft │
└──────────┘
is null мен is not null — бостық туралы сұраудың жалғыз тәсілі.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптар — сабақтың соңында.
create tableсоңындаstrictне үшін тұр және онсыз не болады?whereжоқupdateнеге қауіпті және қателіктен қай екі сөз құтқарады?where cover = nullмұқабасыз жолдарды неге таппайды?
Тапсырма
Міндетті. Кестеге әдепкі мәні 'kz' болатын lang бағанын қосыңыз. Орысша төртінші мақала салыңыз да, бір сұраныспен қазақша мақалаларды сөз саны бойынша сұрыптап шығарыңыз. Содан кейін ең қысқа мақаланың words мәнін 200-ге дейін көтеріңіз — бір пәрменмен, where-мен, әрі changes() тексеріңіз.
Қалауыңызша.
- Сол
slug-пен екінші мақала салыңыз да, дерекқор не айтатынын оқыңыз. create tableішіненstrictалып тастап,wordsішіне'көп'жолын салыңыз.select typeof(words)не қайтаратынын қараңыз.beginішіндеwhereжоқupdateжазып,changes()қараңыз да, кері қайтарыңыз.
Блогта бұл қайда тұрады
articles кестесі — блогтың болашақ қоймасы. Бірақ мақала сирек жалғыз жүреді: оған пікірлер, кейінірек тегтер келеді. Оларды сол кестеге салуға болмайды, ал келесі сабақ — екі кестені кілтпен байланыстырып, оларды бір сұраныспен қайта жинау туралы.
Қарыздар. Индекс жасаған жоқпыз — төрт жолда бұл байқалмайды, ал он мыңда slug бойынша іздеу түгел қарап шығуға айналады. Уақыт мәтін болып сақталады, өйткені SQLite-та күнге арналған бөлек тип жоқ.
Жауаптар
Жауаптарды көрсету
strictбаған типтерін сақтауды талап етеді. Онсыз SQLiteintegerбағанына'abc'салуға келісіп, үндемей қалады, ал сіз бұл туралы бір аптадан кейін, бағдарлама оған бірлік қосқысы келгенде білесіз.- Өйткені
whereжоқupdateбүкіл кестені өзгертеді, әрі ескерту болмайды:changes()бір жолды емес, бәрін көрсетеді. Басындағыbeginмен соңындағыrollbackқұтқарады — өзгерістер болмағандай кері қайтады, ал сан көз алдыңызда тұрады. - Өйткені
null— мән емес, жоқтық белгісі, әрі онымен салыстыру «ақиқат» та, «жалған» да емес, «белгісіз» береді. Жауапқа шарты ақиқат жолдар ғана түседі, сондықтан бірде-біреуі түспейді.is nullарқылы сұрау керек.
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.