Jak zamienić stringa na wyrażenie logiczne?

0

Witajcie,

Jeden z moich kolegów z pracy przyszedł zapytać jak w Delphi zamieniamy stringa na wyrażenie logiczne. W pierwszej chwili nie załapałem o co chodzi ale w dużym uproszeniu weźmy na przykład dowolną bazę danych: Tabela w niej x pól -> robimy na niej zapytanie

select * from tabela

Teraz mój kolega w aplikacji ma edit w którym można wpisać dowolny warunek /warunki ograniczające zakres rekordów czyli np.:

field2 > 0 and field3 <= 100 or field4 = true or field2 < 100 and (field3 > 100 and field4 = false) 

W bazie danych wystarczy dokleić taki string do where i odpalić przez execute, a baza sama sobie to przekonwertuje na zapytanie, sprawdzi jego poprawność i zwróci listę wyników (nie iteresuje nas w tym wypadku SQLInjection). Sęk w tym, że kolega ma taką tabelę (nasz TStringGrid/TDBGrid) i musi to "przefiltrować" używając warunku z edita. Kolega ma to napisane w QT, a dane są z pliku więc niewiele mu pomogłem ale zacząłem się zastanawiać czy jest jakiś sposób aby zrobić to w delphi? Fakt można zrobić memtable i użyć metody filtered = true i filter = ... na np TFDQuery (FireDAC) pytanie co w przypadku gdy nie ma bazy, a dane wyświetlane są z pliku. Plik ma przykładowo 10gb danych i załadowanie całości do pamięci odpada. Trzeba zatem zrobić ręczne przeszukanie całego pliku rekord po rekordzie używając wskazanego w edicie filtra, jeśli spełnia założenia logiczne (rekord) to rzucamy go na ekran. Robił ktoś z was coś takiego? Jakie macie pomysły?

1

Tak. W COBOLu / mainframe czytanie jest na tyle szybkie że działa to migiem.
W Pascalu / Delphi wykorzystałbym do tego czytanie rekordowe.

Inaczej będzie trzeba robić raczej pre-processing (np. załadowanie do bazy SQL komendą typu "bulk load" - bez transakcji - a później procesowanie tych danych SQLem).
http://erictheturtle.blogspot.com/2009/05/fastest-bulk-import-into-sqlite.html

A, no i oczywiście z założeniem że nie mamy sortowania przed filtrowaniem / grupowaniem.
Bo do sortowania na mainframe był specjalny tool (DFSORT), na PC/unix jest sort (ale ograniczony), na PC/Win to nie wiem.

Co do samego parsowania wyrażeń to trzeba byłoby wtedy (bez SQLa) pisać własny parser. Nie jest to może miłe, ale jest możliwe.
Można np. wykorzystać do tego wyrażenia w stylu lambd / FP.
Albo normalny parser: https://github.com/RomanYankovsky/ndyacclex

0

Trzeba parser zrobić, który zamieni stringa na odpowiednie operacje.

Nie stosując żadnych algorytmów i metod optymalizacyjnych, to wystarczy:

Zawsze przeszukiwać całą bazę danych i dla każdego rekordu zwracać zmienne wszystkich pół.

Stringa sprasować, lub na przykład zrobić logiczną odwrotną notację polską i zwrócony true lub false będzie oznaczał czy wyświetlić rekord.

I tak otrzymasz ograniczony zbiór przez logiczne warunki w prosty sposób sparsowane.

0

No kolega właśnie tak to robi, że klepie parser ale z każdym elementem gdy już myśli, że jest ok tester pyka taki przykład, że wszystko mu się wywala. W gruncie rzeczy to nie jest prosty algorytm. Uwzględniając nawiasy i mnogość typów pól to ilość kombinacji jest spora dlatego pytam o jakieś inne bardziej przyjazne rozwiązanie.

0

Jak trudne jak łatwe:
Warunek logiczny
a = b and (c > 9 or d < 10)

Odwrotna logiczna notacja Polska:
a b = c 9 > d 10 < or and

Wrzucasz na stos od lewej do prawej.

Na górze stostu masz and
Logiczne elementy, rekurencyjnie rozwijasz, a dane podstawiasz pod ostatnio wybrany logicznie element.

  1. and
    Schodzisz w dół rekurencyjnie
  2. or - w dół
  3. < - w dół
  4. 10 - wartosc
  5. d - wartosc
  6. doszedłeś na sam dół rozwiązujesz pierwszą logikę.
    d < 10 zwracasz do góry wartość
  7. or wymaga spełnienia jednej z dwóch wartości jak jest true zwrasz do góry, i pomijasz 1 raz 3 elementy głębokości na stosie, a jak nie to idziesz w dół pobierasz następne 3 elementy.
  8. załóżmy, że było true, pomijasz pop, pop, pop elementy
  9. następny element = logiczny
  10. pobierasz wartosc, wartosc
  11. rozwijasz rownanie i masz logiczną wartość, którą zwracasz do góry.
  12. u góry masz and tylko i porównujesz zwrócone rekurencyjnie wartości i to jest logiczna prawda równania.
1

Nie do końca rozumiem, bo opisałeś jakby dwa problemy:

  1. Nie możność stosowania SQL jesli dane są z pliku.
  2. Kwerenda SQL w stringu - jak ją rozbić na mniejsze logiczne artefakty.

Co do Ad. 1 to Firedac ma takie coś jak Local SQL - poczytaj sobie - może pomoże
Ad. 2. Odwrotna notacja polska.

1

Robił ktoś z was coś takiego?

Robił, robił...

Jakie macie pomysły?

Ba, ja mam nawet gotowca ;-)
Ale pod maską jest FireDAC i nie do ładowania danych do MemTable, a tylko i wyłącznie do parsowania wyrażenia quasi SQL.
Tak naprawdę da się to zrobić w ten sposób, że możesz pisać dowolne wyrażenie z wykorzystaniem i zgodne silnikiem FireDAC.
Możesz w tym silniku parsowania wyrażeń rejestrować własne funkcje.

Ja używam tego mechanizmu do filtrowania listy obiektów. Obiekty są w TList<TMyClass> i mogę pisać wyrażenie SQL do filtrowania tej listy na podstawie wartości właściwości.
Podobne w działaniu jest Fluent Query:
https://github.com/malcolmgroves/FluentQuery

Jednakże ja mam na myśli tylko i wyłącznie przedstawienie pomysłu na ewaluację wyrażenia zgodnego z SQL, a na dowolnym źródle danych.
Czyli dokładnie to, o co pytasz.

Jeśli FireDAC nie jest przeszkodą, to mogę pomóc...

Zresztą, to jest opisane w dokumentacji ino trzeba wiedzieć czego szukać i mieć "pomysła", czyli jak zawsze :)
http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=Writing_Expressions.html

1 użytkowników online, w tym zalogowanych: 0, gości: 1