Oznámení
jak na TOP v SQL? (pro MSSQL)
před 10 lety
- wdolek
- Člen | 331
pouzivam MSSQL 2008 server, k nemu se pripojuji pres ODBC. uz nejakou dobu si lamu hlavu, jak dynamicky sestavit SQL dotaz. nasel sem nejake priklady s modifikatory – lmt a ofs …
potreboval bych jednoduse poskladat SQL:
- pokud zadam „limit“, aby se pridalo „TOP n“ na zacatek
- pokud zadam „offset“, aby se do podminky pridal takovy ten zrudny subquery
- pokud „limit“ nezadam, aby se nepridalo samozrejme zadne TOP natoz nejaky subquery
ale jak na to? jak na to pri pouzivani DibiFluent? vim si rady tak s pridanim te podminky (pridat k DibiFluent ->where(' …zrudne subquery… ', $l, $o) i kdyz je mi jasne, ze by to slo snad i cistejs – ze by samotna subquery byla vyrobena nejakym dalsim DibiFluent (?)…
zde jsou SQL, ktere bych chtel dynamicky skladat:
… ??? TeXy ma nejaky zvlastni problem s SQL ??? … nemuzu je sem zaboha
vepsat :P
pri pouziti DibiFluent
$stmt = $db->select('*')->from('foo');
if ( ... $limit ... $offset ... ) {
$stmt->top( $limit ); // ???
$stmt->where( {nejak pridat subquery z jineho DibiFluent?} );
}
if ( ... xxx ... ) {
$stmt->where('something = %s', 'xxx');
}
Editoval wdolek (4. 8. 2009 15:01)
před 10 lety
- romansklenar
- Člen | 657
Zkusil bych to nějak zkombinovat s modifikátory %ofs
a
%lmt
, ty by si měl driver sám správně převést nezávisle
na db.
před 10 lety
- PetrP
- Člen | 587
…a DibiFluent má tuto metodu:
$stmt->limit(10);
Nicméně DibiMssqlDriver nemá offset implementovanej viz api
Takže bud můžeš na davida tlačit aby to implementoval, nebo skusit DibiMssqlDriver rozšířit sám. Tedy jestli to implementovat vůbec nějak jde…
před 10 lety
- wdolek
- Člen | 331
romansklenar: jenze me jde o samotne poskladani toho query. nejak se mi nechce do skladani stringu … navic se mi jednou nejak podarilo, ze mi dibi samo do query nakladlo „TOP n“ … jenze uz nevim jak, a kdyz sem prochazel zdrojaky, nasel sem jen, ze se vklada „SELECT TOP *“ (ano, vcetne te hvezdicky)
PetrP: tam bude problem v tom, ze pouzivam to zlotrile odbc :( takze
i kdyby to bylo v MSSQL driveru, tak je mi to naprd :(
a co se tyce implementace pro MSSQL – tak TOP … WHERE id NOT IN (subquery)
… to je az od verze serveru 2008, u drivejsich se to musi resit zajimavejsi
magii.
a navic – ackoliv bych rad pomohl s vyvojem – kdyz hledim do zdrojaku,
tak proste vubec nemam poneti, co se kde deje, proc, jak, … :((
zkratka – stacilo by jen nejak skladat SQL – s tim, aby se to nejak samo escapovalo… to by mi mozna prozatim stacilo :P nejak bych si s tim poradil – porad by to bylo lepsi nez skladat proste nejaky string a pak se desit nejake injection…
před 10 lety
- PetrP
- Člen | 587
Přehlídl jsem, ale DibiOdbcDriver ma nemlich tu samou metodu, úplně stějně implementovanou/neimplementovanou.
Tedy platí to samé. Tobě ten limit nefunguje tak jak tady ja nebo roman píšem? Můžeš uvést konkrétní kus kédu který nefunguje.
Editoval PetrP (5. 8. 2009 9:21)
před 10 lety
- wdolek
- Člen | 331
public function applyLimit(&$sql, $limit, $offset)
{
// offset support is missing
if ($limit >= 0) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ')';
}
if ($offset) throw new InvalidArgumentException('Offset is not implemented in driver odbc.');
}
nezda se mi, ze by tato funkce delala zrovna to, co ja potrebuji. nemluve o tom, ze stejne moc nerozumim, jak ji aplikovat. z toho jak na to koukam to udela vyber TOP zaznamu z nejakeho query – uz to neresi prave offset, ktery potrebuji.
-- obycejny select
SELECT [a], [b], [c] FROM [foo];
-- obycejny select s podminkou
SELECT [a], [b], [c] FROM [foo] WHERE [something] = 'xxx';
-- select N zaznamu od Mte polozky
SELECT TOP %lmt [a], [b], [c] FROM [foo] WHERE ([id] NOT IN (SELECT TOP %ofs [id] FROM [foo]));
-- select N zaznamu od Mte polozky s podminkou
SELECT TOP %lmt [a], [b], [c] FROM [foo] WHERE ([id] NOT IN (SELECT TOP %ofs [id] FROM [foo])) AND ([something] = 'xxx');
před 10 lety
- wdolek
- Člen | 331
stacilo by mi, aby:
- slo pridat k „SELECT“ jeste „TOP %lmt“
- pridat do podminek nejake query od jinud
narpiklad kdyby slo:
$sub_stmt = $db->select('id', 666)->from('foo');
$stmt = $db->select('a, b, c', 10)->from('foo')->where('id NOT IN (%sql)', $sub_stmt);
SELECT TOP 10 [a], [b], [c] FROM [foo] WHERE [id] NOT IN (SELECT TOP 666 [id] FROM [foo]);
nanestesti „->select(<string>, <int>)“ je ma fikce :( a „applyLimit“ by to cele query zabalil do zavorek, a uz by se tam spatne pridavala ta podminka pro offset… (nebo me alespon nenapada jak)
před 10 lety
- PetrP
- Člen | 587
Takže ještě jednou: Offset is not implemented in driver odbc.
Zkoušel jsem to nanečisto (tedy jen to co mi driver generuje za sql, stroj
kde ověřit funkčnost nemám)
a zjistil jsem ze DibiFluent::limit() skutečně nefunguje, myslel jsem si že
bude volat driver->applyLimit a nedělá to (Davide není to bug?), ale přes
modifikátor to funguje
dibi::query('SELECT FROM xxx %lmt',10);
SELECT TOP 10 * FROM (SELECT FROM xxx )
To je správně ne?
A tohle je jedine řešení jak přidat ofset
dibi::query('SELECT FROM xxx WHERE id NOT IN (SELECT TOP 10 id FROM xxx) %lmt',10);
SELECT TOP 10 * FROM (SELECT FROM xxx WHERE id NOT IN (SELECT TOP 10 id FROM xxx) )
Nějaký obecný mechanizmus (pro začlenění do driveru) na to vymyslet nejde.
před 10 lety
- wdolek
- Člen | 331
Takže ještě jednou: Offset is not implemented in driver odbc.
ano, to vim :) a nikde se nepru, ze by to slo, nebo melo jit (protoze to ani pro ODBC takto zaridit nejde)
Nějaký obecný mechanizmus (pro začlenění do driveru) na to vymyslet nejde.
ono mi tak ani nejde o obecny mechanismus, ale jak to SQLko slozit nejak
„dynamicky“ – nanestesti potrebuji k tomuto dotazu pridavat dalsi
podminky (kde podminkou je samozrejme i ten dany limit).
potiz mam s tim, ze nyni mohu dotaz modifikovat pouze:
$stmt = $db->select('*')->from('table');
if ($whatever) {
$stmt->where('something = %s', $blah);
}
$result = $stmt->execute();
… tedy pridat podminku do SQL je velice snadne. resim zde ale,
jak mohu modifikovat nejak vyrazneji cele query pomoci
DibiFluent
. v mem pripade, pridani limitu spociva v: pridani
TOP n
hned za SELECT
a pak pridani podminky za
WHERE
; resim zde, zda-li ma dibi nejakou funkci ala
StringBuffer – jedine, co nyni svedu je proste slozit string vlastnimi silami
na zaklade milionu podminek…
$sql = 'SELECT ';
$where = array();
if ($limit > 0 && $offset >= 0) {
$sql .= 'TOP ' . $limit;
array_push($where, 'id NOT IN (SELECT TOP ' . $offset . ' id FROM foo)');
}
if ( ... ) {
...
}
...
a to znamena, ze vlastne dibi v tomto pripade nevyuziji. jak sem psal vyse,
ono by mi uplne stacilo, kdybych mohl ovlivnit pomoci dibi cast
SELECT
/ SELECT TOP n
(mit moznost pridat
TOP
) … nic vic, pak uz je to hracka (viz predesly post a ukazka
kodu, jak by to asi mohlo vypadat). jenom kvuli tomu, ze toto neumim (neumi dibi
/ nevim o teto moznosti) musim string skladat sam „rucne“.