Linux за българи: Форуми

Програмиране => Общ форум => Темата е започната от: laskov в May 26, 2021, 09:50



Титла: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: laskov в May 26, 2021, 09:50
Или: Какъв е правилният начин? Пробвах така:

Вариант 1
Цитат
Q1.SQL="SELECT ID FROM t WHERE f=0;"
while not Q1.EOF do begin
  Q2.SQL="UPDATE t SET f=123 WHERE ID=Q1(ID);";
  Q1.Next;
end;
Вариант 2
Цитат
Q1.SQL="SELECT ID FROM t WHERE f=0;"
while not (Q1.BOF and Q1.EOF) do begin
  Q2.SQL="UPDATE t SET f=123 WHERE ID=Q1(ID);";
  Q1.REFRESH;
end;

t е временна таблица и може да е на MariaDB сървър в локалната мрежа или да е sqlite-3 локално на машината, на която работи програмата.

Кодът е примерен, а това 123 не е 123 а е VARCHAR с уникална стойност.

Експериментите са с неясен резултат. Ако са на сървър в мрежата най-често работи, но понякога се получават грешки. Предполагам, че е свързано с кеширане, бързодействие, промяна в реда на изпълнение на сървъра ...
Ако е на локалната машина, като че ли sqlite не позволява да се изпълни Q2 докато е акпивна Q1.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: Naka в May 26, 2021, 12:07
Такова не съм правил. обаче.... тук

https://dev.mysql.com/doc/refman/8.0/en/update.html

след средата на страницата (най-отдолу) има описан такъв случай. с три работещи примера. На мен най ми хареса най-последния (който е най-отдолу)

Код:
UPDATE items,
       (SELECT id, retail / wholesale AS markup, quantity FROM items)
       AS discounted
    SET items.retail = items.retail * 0.9
    WHERE discounted.markup >= 1.3
    AND discounted.quantity < 100
    AND items.id = discounted.id;

Сега  доколкото разбирам ключа от бараката е следния:
1. Да се ползва multi-table update, като втората таблица, която е пак същата е описана като alias. (AS discounted)

UPDATE items, (...) AS discounted  SET ....

2. и друга хитрост има, че sub-query -то (SELECT id,....) е преместено в частта където се описват таблиците, по които ще се действа - т.е FROM частта. (То тука FROM няма, има UPDATE, но все тая..)

https://www.mysqltutorial.org/mysql-subquery/
Цитат
MySQL subquery in the FROM clause
-----------------
When you use a subquery in the FROM clause, the result set returned from a subquery is used as a temporary table. This table is referred to as a derived table or materialized subquery.






Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: remotexx в May 26, 2021, 16:52
Колега,  темата уж е за SQL ама май не е...
Дай повече инфо
Инак /ако заглавието  е вярно, поне в началото/

Код
GeSHi (SQL):
  1. UPDATE t
  2.  SET f = 123
  3.  WHERE f = 0
  4.  


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: Naka в May 26, 2021, 20:29
И из това се чудих защо да не може така.... Ама навсякъде казват че не можело на едно и също поле?. Кое ще изпълни първо - условието или ъпдейта. Няма как да знаеш как работи вътрешно.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: laskov в May 26, 2021, 20:47
remotexx, не искам навсякъде да запиша 123. По-горе написах, че кодът е примерен, а 123 всъшност е уникален VARCHAR

Naka, този вариант ще е добър за работа с MariaDB сървъра, но аз, с цел по-голямо бързодействие, май се ориентирах към sqlite. Ще експериментирам още.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: remotexx в May 27, 2021, 06:53
Ами то има общо взето 2 начина за справяне с тоя проблем:

1) програмистки - колегата мисли като програмист обаче отказва да назове езика за програмиране който (ще) ползва (упорито стои там т'ва SQL в началото) та ще караме с псевдокод
- та има параметризирани заявки a.k.a. prepared queries
подготвя се заявка от вида UPDATE t SET f = ? WHERE ID = ? -- може и с именунвани параметри
и после в цикъл се чете от файл (или там отдето се четат данните) и се заместват ID, F ст-те

2) SQL начина е следния
- прави се втора таблица (временна или постоянна): ID, F (new value)
- попълва се с новите данни
- прави се UPDATE от SQL JOIN
Код
GeSHi (SQL):
  1. -- table v: ID, NewValue
  2. UPDATE t SET t.f = v.NewValue
  3. FROM t INNER JOIN v ON t.ID=v.ID
  4. WHERE t.ID BETWEEN 1 .. 100;
  5.  

NB! Ако се търси UPSERT фунционалност там вече зависи от SQL диалекта, ама колегата тъй и не уточни какъв е точно сървъра..


3) само за пълнота и в SQL може да се направи stored procedure с параметри и да се вика само тя с различни ID,F комбинации (ама е същото като 1. само че езикът е SQL)

Код
GeSHi (SQL):
  1. EXEC sp_executesql N' SELECT * FROM table_t WHERE first_name = @parameter ', N'@parameter VARCHAR(8000)', N'John'


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: go_fire в May 27, 2021, 07:43

отказва да назове езика за програмиране който (ще) ползва (упорито стои там т'ва SQL в началото) та ще караме с псевдокод



За толкова време не разбра, че колегата пише (почти единствено) на езика, на който започваш кариерата си. Само, че в твоя случай това е турбо-варианта, а неговия е Фрий.

п.п. Ще те учудя ли, ако ти кажа, че и Борланд, и Турбо* си съществуват и даже струват някакви много милиарди на борсата.



NB! Ако се търси UPSERT фунционалност там вече зависи от SQL диалекта, ама колегата тъй и не уточни какъв е точно сървъра..

В по-горното мнение споменава, че за момента е на Марчето. Но щял да мигрира на Лайт за бързодействие?! Разбирам да е за простота и по-малко ресурси, ама за бързина точно. Как да е.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: remotexx в May 27, 2021, 08:21
Борланд (и Турбо-то) може и да си съществуват още но не са същите. Инженерите им ги прилапа Майкрософт да спасяват .Нет-я и с право -спасиха го - версия 0.х че и 1.х беха големи бози и 1.5 беше вече на умирачка (Джава-та за малко да победи) обаче М$ инженерчетата забелязаха навреме че по форумите им една група 'чужди' инженери задват правилните въпроси а и на всичкото отгоре им знаят и правилниите отговори (т.е. какво трябва да се оправи и какво добави в новия .Нет 2.0 та да се оправи) и си ги купиха цялата група наведнъж (за неназована сума) а Борланд се оттегли към ALM сегмента

А бизнеса (за който споменаваш) отдавна го продадоха на едни дето предимно и само с БД се занимават (embarcadero) - инак продуктите са същите
https://www.embarcadero.com/products/delphi

Delphi 10.4.2
Build Native Apps 5x Faster For
Windows, Android, iOS, macOS, and Linux
и с право

че има и безплатна версия, ако иска колегата може и нея да ползва - ако му върши работа
https://www.embarcadero.com/products/delphi/starter

Delphi Community Edition
Full-Featured Free Delphi IDE for Creating Native Cross-Platform Apps

би трябвало да му свърши работа...
- Direct access REST services and local/embedded databases such as InterBase, SQLite, MySQL, and more.
- Licensed for use until your individual revenue from Delphi applications or company revenue reaches $5,000 US or your development team expands to more than 5 developers

който иска с/с++ има и с++ безплатно
https://www.embarcadero.com/free-tools


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: remotexx в May 27, 2021, 08:27
...тъй като въпросът все още е (само) за (чист) SQL (а не за SQL DB +Turbo-не-нам-к'во-си)
SQLite versions:

https://stackoverflow.com/questions/19270259/update-with-join-in-sqlite
Код
GeSHi (SQL):
  1. -- UPDATE from JOIN
  2. UPDATE
  3.      software
  4. SET purchprice = (SELECT purchprice
  5.                  FROM softwarecost
  6.                  WHERE id = software.id)
  7. WHERE EXISTS (SELECT purchprice
  8.                  FROM softwarecost
  9.                  WHERE id = software.id)
  10.  
като where EXISTS се ползва само щото без него ще присвои ст-т NULL ако няма такъв ред във втората таблица

-- UPSERT - малко странен синтаксис ама то при UPSERT вскеи вендор си има собствено виждане
https://www.sqlite.org/lang_UPSERT.html


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: laskov в May 27, 2021, 09:54
...
...
2) SQL начина е следния
- прави се втора таблица (временна или постоянна): ID, F (new value)
- попълва се с новите данни
- прави се UPDATE от SQL JOIN
Код
GeSHi (SQL):
  1. -- table v: ID, NewValue
  2. UPDATE t SET t.f = v.NewValue
  3. FROM t INNER JOIN v ON t.ID=v.ID
  4. WHERE t.ID BETWEEN 1 .. 100;
  5.  
...
...
Ето това очаквах - втора таблица. В случая с sqlite дори ще е отделна дб.
Иначе да, не съм споменал езика, но проблемът ми е в работата с базата данни. Аз съм дървен програмист, но и това си има степени и предполагах, че тръгвам да го правя по възможно най-дървения начин. А сървъра съм го уточнил още в първия пост.

go_fire, предполагам, (а и четох,) че локален sqlite ще е по-бърз от MariaDB в мрежата. Все пак това ще е in memory db на локалната машина.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: go_fire в May 27, 2021, 10:02
go_fire, предполагам, (а и четох,) че локален sqlite ще е по-бърз от MariaDB в мрежата. Все пак това ще е in memory db на локалната машина.

Най-вероятно е така. Аз все пак не съм специалист по системи за управление на бази от данни.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: Naka в May 27, 2021, 11:00
Сещам се още един начин. Може да работи а може и да не. Идеята е сравнението да се махне от WHERE частта а да се направи с вградена функция в SET-a.

Код:
UPDATE t
  SET f = if(f = 0, 123, f) ;

според https://dev.mysql.com/doc/refman/8.0/en/update.html
ако имаме следния примерен код:

Цитат
if you access a column from the table to be updated in an expression, UPDATE uses the current value of the column. For example, the following statement sets col1 to one more than its current value:
UPDATE t1 SET col1 = col1 + 1;
то mysql-a в дясната част използва текущата (непромената) стойност на полето. т.е col1 (f) ни е гарантирано!

така ще се опита да ъпдейтне всичките редове, щото няма WHERE, но само някои, които отговарят на условието ще се ъпдейтнат. (То пак може да имаме  WHERE с разни други условия)
Но пък на друго място е казано, че
Цитат
If you set a column to the value it currently has, MySQL notices this and does not update it.
така, че ще работи бързо. Тези if(), case ..... изобщо всичките му вградени функции са много бързи.


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: remotexx в May 27, 2021, 17:19
Некой забележки
- Мисля че беше IIF - Immediate IF (а не IF) MySQL оператора, но може и да е имало (скорошни) промени
- доколкото разбрах той по-скоро ще иска CASE WHEN ID == 11 THEN 1 WHEN ID ==2 THEN 22 etc.
- и да - за сървъри които не поддържат TVP (Table Value parameters) динамичен SQL (като горния) от страна на клиента е спасението, но си има и некои ограничения напр. да внимава да не прехвърли макс., размер на пакета който сървъра може да обработи - мисля за MySQL по подразбиране 8 Мб и май можеше да се наглася от админа до 16 (по новите версии може и да може до повече не го следя от неколко декади mySQL-a) и.. дотам - като удариш тоя лимит трябва да затваряш текущата и да почваш нова SQL команда

т.е. колега ако ти е сравнително малка таблицата или с малко обновявания кото ще се съберат в една завка (за цялата таблица с новти ст-ти) "мрежовата цена"  ще ти е само "времето за изпълнение на една заявка по мрежата" - няма да е много бавно

П.П. Unfortunately MySql didn't implement table-valued parameters, but alternatives do exist:
- TEMP table
- JSON - MYSQL 8 supports JSON tables, so you could load your results into a JSON variable and select from that variable using the JSON_TABLE() command.
- CSV string +parse in UDF /Using a delimited string ("str1,str2,str3") which significantly downgrades performance, especially when the string is very long./
- и класически метод който си работи от време оно който описах по-горе:
който има няколко варианта (вече го правят и с временна таблица от кода направо)
при всички тези варианти по-долу трябва да се внимава да не се превиши размера на пакета - според както е настроен сървъра

Код
GeSHi (SQL):
  1. -- класически стил
  2. UPDATE table1 SET val1= CASE id
  3.                          WHEN 1 THEN 5
  4.                          WHEN 3 THEN 8
  5.                          WHEN 4 THEN 7
  6.                          ELSE val1
  7.                        END,
  8.                 val2= CASE id
  9.                          WHEN 2 THEN 13
  10.                          WHEN 4 THEN 5
  11.                          ELSE val2
  12.                        END
  13.             WHERE id IN (1, 2, 3, 4);
  14.  

-- съвременен вариант който не съществуваше до скоро (но още са далеч от М$ TVP)
-- със или без темп таблица
Код
GeSHi (SQL):
  1. INSERT INTO TABLE (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
  2. ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);
Код
GeSHi (SQL):
  1. UPDATE my_table m
  2. JOIN (
  3.    SELECT 1 AS id, 10 AS _col1, 20 AS _col2
  4.    UNION ALL
  5.    SELECT 2, 5, 10
  6.    UNION ALL
  7.    SELECT 3, 15, 30
  8. ) vals ON m.id = vals.id
  9. SET col1 = _col1, col2 = _col2;

П.П.П. Внимание - горните "мрежови" алтернативи задължително да се ползват в транзакция - за всеки слулчай ако напр. ред 1000 от 1М фърли грешка (напр. INT OVERFLOW) да не остане таблицата само наполовина обновена


Титла: Re: SQL. Пиша там, откъдето чета. Как го правят майсторите?
Публикувано от: laskov в May 28, 2021, 11:33
remotexx, Naka, go_fire, благодаря за коментарите! Ще падне много четене :)