Автор Тема: SQL. Пиша там, откъдето чета. Как го правят майсторите?  (Прочетена 9634 пъти)

laskov

  • Напреднали
  • *****
  • Публикации: 3166
    • Профил
Или: Какъв е правилният начин? Пробвах така:

Вариант 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.
Активен

Не си мислете, че понеже Вие мислите правилно, всички мислят като Вас! Затова, когато има избори, идете и гласувайте, за да не сте изненадани после от резултата, и за да не твърди всяка партия, че тя е спечелила, а Б.Б. (С.С., ...) е загубил, а трети да управлява.  Наздраве!  [_]3

Naka

  • Напреднали
  • *****
  • Публикации: 3395
    • Профил
Такова не съм правил. обаче.... тук

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.




« Последна редакция: May 26, 2021, 12:19 от Naka »
Активен

Perl - the only language that looks the same before and after encryption.

remotexx

  • Напреднали
  • *****
  • Публикации: 3210
    • Профил
Колега,  темата уж е за SQL ама май не е...
Дай повече инфо
Инак /ако заглавието  е вярно, поне в началото/

Код
GeSHi (SQL):
  1. UPDATE t
  2.  SET f = 123
  3.  WHERE f = 0
  4.  
Активен

Naka

  • Напреднали
  • *****
  • Публикации: 3395
    • Профил
И из това се чудих защо да не може така.... Ама навсякъде казват че не можело на едно и също поле?. Кое ще изпълни първо - условието или ъпдейта. Няма как да знаеш как работи вътрешно.
Активен

Perl - the only language that looks the same before and after encryption.

laskov

  • Напреднали
  • *****
  • Публикации: 3166
    • Профил
remotexx, не искам навсякъде да запиша 123. По-горе написах, че кодът е примерен, а 123 всъшност е уникален VARCHAR

Naka, този вариант ще е добър за работа с MariaDB сървъра, но аз, с цел по-голямо бързодействие, май се ориентирах към sqlite. Ще експериментирам още.
« Последна редакция: May 26, 2021, 20:49 от laskov »
Активен

Не си мислете, че понеже Вие мислите правилно, всички мислят като Вас! Затова, когато има избори, идете и гласувайте, за да не сте изненадани после от резултата, и за да не твърди всяка партия, че тя е спечелила, а Б.Б. (С.С., ...) е загубил, а трети да управлява.  Наздраве!  [_]3

remotexx

  • Напреднали
  • *****
  • Публикации: 3210
    • Профил
Ами то има общо взето 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'
« Последна редакция: May 27, 2021, 06:57 от remotexx »
Активен

go_fire

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 8780
  • Distribution: Дебиан Сид
  • Window Manager: ROX-Desktop / е17
  • кашик с гранатомет в танково поделение
    • Профил
    • WWW

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



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

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



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

В по-горното мнение споменава, че за момента е на Марчето. Но щял да мигрира на Лайт за бързодействие?! Разбирам да е за простота и по-малко ресурси, ама за бързина точно. Как да е.
« Последна редакция: May 27, 2021, 07:50 от go_fire »
Активен

В $por4e2 e истината  ;)

***

Aко даваха стипендия за най-глупави, щях да съм човека с най-много Mини Kупъри

***

Reborn since 1998 || 15.09.2007 totally М$ free && conscience clear

remotexx

  • Напреднали
  • *****
  • Публикации: 3210
    • Профил
Борланд (и Турбо-то) може и да си съществуват още но не са същите. Инженерите им ги прилапа Майкрософт да спасяват .Нет-я и с право -спасиха го - версия 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
Активен

remotexx

  • Напреднали
  • *****
  • Публикации: 3210
    • Профил
...тъй като въпросът все още е (само) за (чист) 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
« Последна редакция: May 27, 2021, 08:33 от remotexx »
Активен

laskov

  • Напреднали
  • *****
  • Публикации: 3166
    • Профил
...
...
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 на локалната машина.
Активен

Не си мислете, че понеже Вие мислите правилно, всички мислят като Вас! Затова, когато има избори, идете и гласувайте, за да не сте изненадани после от резултата, и за да не твърди всяка партия, че тя е спечелила, а Б.Б. (С.С., ...) е загубил, а трети да управлява.  Наздраве!  [_]3

go_fire

  • Global Moderator
  • Напреднали
  • *****
  • Публикации: 8780
  • Distribution: Дебиан Сид
  • Window Manager: ROX-Desktop / е17
  • кашик с гранатомет в танково поделение
    • Профил
    • WWW
go_fire, предполагам, (а и четох,) че локален sqlite ще е по-бърз от MariaDB в мрежата. Все пак това ще е in memory db на локалната машина.

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

В $por4e2 e истината  ;)

***

Aко даваха стипендия за най-глупави, щях да съм човека с най-много Mини Kупъри

***

Reborn since 1998 || 15.09.2007 totally М$ free && conscience clear

Naka

  • Напреднали
  • *****
  • Публикации: 3395
    • Профил
Сещам се още един начин. Може да работи а може и да не. Идеята е сравнението да се махне от 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 ..... изобщо всичките му вградени функции са много бързи.
« Последна редакция: May 27, 2021, 11:24 от Naka »
Активен

Perl - the only language that looks the same before and after encryption.

remotexx

  • Напреднали
  • *****
  • Публикации: 3210
    • Профил
Некой забележки
- Мисля че беше 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) да не остане таблицата само наполовина обновена
« Последна редакция: May 27, 2021, 17:36 от remotexx »
Активен

laskov

  • Напреднали
  • *****
  • Публикации: 3166
    • Профил
remotexx, Naka, go_fire, благодаря за коментарите! Ще падне много четене :)
Активен

Не си мислете, че понеже Вие мислите правилно, всички мислят като Вас! Затова, когато има избори, идете и гласувайте, за да не сте изненадани после от резултата, и за да не твърди всяка партия, че тя е спечелила, а Б.Б. (С.С., ...) е загубил, а трети да управлява.  Наздраве!  [_]3