Gå til innhold

Legge til en WHERE i et eksisterende SQL uttrykk


Anbefalte innlegg

Folkens. Har følgende behov:
​I våre programmer brukes SQL statements både fra EntityFramework og fra andre drivere som sender SQL statements rett til SQL serveren.  Jeg har behov for å lure inn et WHERE i samtlige statements som sendes uavhengig hvor de kommer ifra.  Tenkte først å bruke en TRIGGER på SQL servere, men det finnes ikke for SELECT.  I .NET verden hara jeg ikke noe problem med å lure dette inn fordi det er jeg som koder POCO klassene.  Men i vårt andre verktøy (Clarion) så er det ikke slik.  Der lages SQL uttrykket av et RTL.  Det fine er at jeg har en callback i dette RTL'et som gir meg SQL uttrykket som blir sendt til SQL serveren før det sendes.  Jeg har der muligheten til å modde uttrykket og dermed lure inn et WHERE uttrykk.  
​Så kom neste problemstilling. Det å parse et generellt SQL uttrykk er ikek veldig enkelt fordi man i utgangspunktet ikke aner noe om uttrykket i det hele tatt og parse rutinene vil i så måte bli veldig kompliserte, og ikek minst, muligheten for feil er overhengende stor.  Så tenkte jeg, kanskje EntityFramework har noe på lur her.

​Gitt følgende pseudokode:


Public static string AddWhere(string Expression)
{
    ​var SQLObjekt  = ettellerannet.Parse(uttrykk);
    ​SQLObject.AddWhere("EnStoredProcedure()");
    Return SQLObject.ToString();
}

​Er dette mulig i det hele tatt ?
 

Lenke til kommentar
Videoannonse
Annonse

Du kan jo dekorere dem med noe sånt:

 

with originalQuery as (
	--orginal spørring
) select * from originalQuery where --nytt predikat

 

Åhhh, nesten i mål :-)

Ideen er kjempe god og virker nesten. Kanskje har du noe flere tips.  Fordi her er følgende problem:

Sett at uttrykket inneholder en join, og at begge tabellene som joines har kolonner med samme navn, da får jeg SQL error som sier at sub Query feiler med duplikat navn.  Altså:

​SELECT a.Id, a.Navn, a.Nummer, b.Id, b.Beskrivelse from Personer a

JOIN Telefoner b on a.Id = b.Id

Dette gir forventet resultat, men

​WITH res as

(

SELECT a.Id, a.Navn, a.Nummer, b.Id, b.Beskrivelse from Personer a

JOIN Telefoner b on a.Id = b.Id

)

SELECT * from res

​Dette derimot resulterer i en feil fordi kolonnen Id dukker opp TO ganger i RES.

Vet det er enkelt å bare aliasifisere kolonnen, men dessverre er dette genererte uttrykk som ikke er så lett å modifisere.

Finnes det en vei rundt dette tro?

Lenke til kommentar

Du mener at with res (id1, navn,nummer, id2, beskrivelse) as ( select...

 

Ikke virker?

 

Jeg kan være helt konkret:

with res as 
(
SELECT TOP 2147483647 A.RECORDFILTER, A.NUMMER, A.NAVN, B.NUMMER, B.PERSONID, B.BESKRIVELSE, B.TELEFON 
FROM  {oj PERSONER A LEFT OUTER JOIN PHONES B ON  A.NUMMER= B.PERSONID }  
WHERE (  A.NAVN = 'Ole' )  
ORDER BY  B.PERSONID ASC, B.BESKRIVELSE ASC
) 
select * from res

Dette gir følgende feilmelding:

Msg 8156, Level 16, State 1, Line 1

The column 'NUMMER' was specified multiple times for 'res'.

Lenke til kommentar

 

Du mener at with res (id1, navn,nummer, id2, beskrivelse) as ( select...

 

Ikke virker?

 

Jeg kan være helt konkret:

with res as 
(
SELECT TOP 2147483647 A.RECORDFILTER, A.NUMMER, A.NAVN, B.NUMMER, B.PERSONID, B.BESKRIVELSE, B.TELEFON 
FROM  {oj PERSONER A LEFT OUTER JOIN PHONES B ON  A.NUMMER= B.PERSONID }  
WHERE (  A.NAVN = 'Ole' )  
ORDER BY  B.PERSONID ASC, B.BESKRIVELSE ASC
) 
select * from res

Dette gir følgende feilmelding:

Msg 8156, Level 16, State 1, Line 1

The column 'NUMMER' was specified multiple times for 'res'.

 

 

 

Du henter ut feltet nummer fra både tabell a og tabell b.

Jeg synes at det er rart at det ikke skulle virke hvis du gir de et alias.

Kan du ikke prøve med denne?

with (RecFilter, Nummer, Navn, Num, PersId, Beskrivelse, telefon) res as 
(
SELECT A.RECORDFILTER
     , A.NUMMER
     , A.NAVN
     , B.NUMMER
     , B.PERSONID
     , B.BESKRIVELSE
     , B.TELEFON 
FROM  PERSONER A 

LEFT OUTER JOIN PHONES B 
  ON A.NUMMER= B.PERSONID
 
WHERE A.NAVN = 'Ole' 
ORDER BY  B.PERSONID ASC
        , B.BESKRIVELSE ASC
) 
select * from res
Lenke til kommentar

 

 

Du mener at with res (id1, navn,nummer, id2, beskrivelse) as ( select...

 

Ikke virker?

 

Jeg kan være helt konkret:

with res as 
(
SELECT TOP 2147483647 A.RECORDFILTER, A.NUMMER, A.NAVN, B.NUMMER, B.PERSONID, B.BESKRIVELSE, B.TELEFON 
FROM  {oj PERSONER A LEFT OUTER JOIN PHONES B ON  A.NUMMER= B.PERSONID }  
WHERE (  A.NAVN = 'Ole' )  
ORDER BY  B.PERSONID ASC, B.BESKRIVELSE ASC
) 
select * from res

Dette gir følgende feilmelding:

Msg 8156, Level 16, State 1, Line 1

The column 'NUMMER' was specified multiple times for 'res'.

 

 

 

Du henter ut feltet nummer fra både tabell a og tabell b.

Jeg synes at det er rart at det ikke skulle virke hvis du gir de et alias.

Kan du ikke prøve med denne?

with (RecFilter, Nummer, Navn, Num, PersId, Beskrivelse, telefon) res as 
(
SELECT A.RECORDFILTER
     , A.NUMMER
     , A.NAVN
     , B.NUMMER
     , B.PERSONID
     , B.BESKRIVELSE
     , B.TELEFON 
FROM  PERSONER A 

LEFT OUTER JOIN PHONES B 
  ON A.NUMMER= B.PERSONID
 
WHERE A.NAVN = 'Ole' 
ORDER BY  B.PERSONID ASC
        , B.BESKRIVELSE ASC
) 
select * from res

 

Jeg tenker at det blir feil fordi det nettopp IKKE er alias på feltene, men bare tabellene:

​SELECT a.Felt, b.Felt from tabell1 a join tabell2 b.....

 

Man kunne aliasifisert dette slik:

SELECT a.Felt as A_Felt, b.Felt as B_Felt....

Men dessverre har jeg ingen påvirkning på dette uttrykket så hvis jeg skal få gjort dette så må jeg lage en relativt komplisert parser. Håpet kansje det var en eller annen SQL automatikk på dette. subqueries har jo eksistert en stund

Lenke til kommentar

 

 

Du mener at with res (id1, navn,nummer, id2, beskrivelse) as ( select...

 

Ikke virker?

 

Jeg kan være helt konkret:

with res as 
(
SELECT TOP 2147483647 A.RECORDFILTER, A.NUMMER, A.NAVN, B.NUMMER, B.PERSONID, B.BESKRIVELSE, B.TELEFON 
FROM  {oj PERSONER A LEFT OUTER JOIN PHONES B ON  A.NUMMER= B.PERSONID }  
WHERE (  A.NAVN = 'Ole' )  
ORDER BY  B.PERSONID ASC, B.BESKRIVELSE ASC
) 
select * from res

Dette gir følgende feilmelding:

Msg 8156, Level 16, State 1, Line 1

The column 'NUMMER' was specified multiple times for 'res'.

 

 

 

Du henter ut feltet nummer fra både tabell a og tabell b.

Jeg synes at det er rart at det ikke skulle virke hvis du gir de et alias.

Kan du ikke prøve med denne?

with (RecFilter, Nummer, Navn, Num, PersId, Beskrivelse, telefon) res as 
(
SELECT A.RECORDFILTER
     , A.NUMMER
     , A.NAVN
     , B.NUMMER
     , B.PERSONID
     , B.BESKRIVELSE
     , B.TELEFON 
FROM  PERSONER A 

LEFT OUTER JOIN PHONES B 
  ON A.NUMMER= B.PERSONID
 
WHERE A.NAVN = 'Ole' 
ORDER BY  B.PERSONID ASC
        , B.BESKRIVELSE ASC
) 
select * from res

 

Heisan!   Leste ikke hele meldingen din!!!   Jeg skal jaggu prøve ut den varianten.  Litt komplisert blir det fordi jeg alikevel må lage en slags parser som finner verdiene i SELECT delen.  Det er i hvertfall en start...

Lenke til kommentar

 

 

 

Du mener at with res (id1, navn,nummer, id2, beskrivelse) as ( select...

 

Ikke virker?

 

Jeg kan være helt konkret:

with res as 
(
SELECT TOP 2147483647 A.RECORDFILTER, A.NUMMER, A.NAVN, B.NUMMER, B.PERSONID, B.BESKRIVELSE, B.TELEFON 
FROM  {oj PERSONER A LEFT OUTER JOIN PHONES B ON  A.NUMMER= B.PERSONID }  
WHERE (  A.NAVN = 'Ole' )  
ORDER BY  B.PERSONID ASC, B.BESKRIVELSE ASC
) 
select * from res

Dette gir følgende feilmelding:

Msg 8156, Level 16, State 1, Line 1

The column 'NUMMER' was specified multiple times for 'res'.

 

 

 

Du henter ut feltet nummer fra både tabell a og tabell b.

Jeg synes at det er rart at det ikke skulle virke hvis du gir de et alias.

Kan du ikke prøve med denne?

with (RecFilter, Nummer, Navn, Num, PersId, Beskrivelse, telefon) res as 
(
SELECT A.RECORDFILTER
     , A.NUMMER
     , A.NAVN
     , B.NUMMER
     , B.PERSONID
     , B.BESKRIVELSE
     , B.TELEFON 
FROM  PERSONER A 

LEFT OUTER JOIN PHONES B 
  ON A.NUMMER= B.PERSONID
 
WHERE A.NAVN = 'Ole' 
ORDER BY  B.PERSONID ASC
        , B.BESKRIVELSE ASC
) 
select * from res

 

Heisan!   Leste ikke hele meldingen din!!!   Jeg skal jaggu prøve ut den varianten.  Litt komplisert blir det fordi jeg alikevel må lage en slags parser som finner verdiene i SELECT delen.  Det er i hvertfall en start...

 

 

Ser ut som dette er veien å gå.  En liten rettelse på syntaxen din though:

​SELECT (a, b, c) res as (.....   <-   Feilet

SELECT res (a, b, c) as (.....   <- Funker

 

Takker for glimrende tips

Lenke til kommentar

Du bruker .net ? Då lager du ikke en egen parser. Bruk Entity Framework eller Dapper (bare to av mange eksempler) for å mappe et SQL resultatsett til .net objekt.

 

Takker for tipset, men hvis du leser mitt innledende spørsmål så har ikke dette noe med .NET å gjøre ;)

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...