Search

onze sponsors

microsoft_logo.gif


 

computrain_logo.JPG

Forum Login | Register
   Forum

 

Subject: Max value van meerdere velden bepalen
Prev Next
You are not authorized to post a reply.

Author Messages
Stephan BussingUser is Offline

Posts:54

27-01-2010 09:05:16 Alert 

Daar ben ik weer

 

nu met de volgende vraag. Ik heb een view (weer een view) waarin de resultaten staan van een vragen lijst. In die view komen o.a. 4 velden voor (Waarde1,.., Waarde4). Nu moet ik van deze velden de hoogste score bepalen. In de velden kan eventueel ook NULL staan. Het lijkt mij dat dit niet mogelijk is om in de view te bepalen, dus het wordt dan, neem ik een een SP die het restultaat van een tijdelijke tabel terug geeft. Denk ik zo.

Mijn idee is dus om de view te gebruiken en hier met een cursor doorheen te loopen om zo van elke vraag de max waarde te bepalen. Of heeft iemand hier een betere oplossing voor. Het resultaat moet in een report gebruikt worden, maar de logica voor het berekenen moet in de resultaatset staan. Dus niet bepaald worden in het rapport. Maw ik moet een kant en klare set leveren.

 

Bedankt maar weer.

André KammanUser is Offline
PASS Nederland

Posts:124


27-01-2010 09:58:09 Alert 

Hoi Stephan,

UNPIVOT is voor dit geval wel een mooie optie volgens mij, wat dacht je van onderstaand voorbeeld ? :

use tempdb
go

Create table score(ID int, waarde1 int, waarde2 int, waarde3 int, waarde4 int)
Insert into score values(1, 8, 7, 8 , 5)
Insert into score values(2, NULL, 5, NULL, 6)
go

Create view vwScore
as
  Select ID, WaardeNr, Score
  From (Select ID, waarde1, waarde2, waarde3, waarde4 From score) pvt
  UNPIVOT (Score FOR WaardeNR in (waarde1, waarde2, waarde3, waarde4)) unpvt
go

Groeten,
André

Hugo KornelisUser is Offline

Posts:19

27-01-2010 10:00:01 Alert 

Hoi Stephan,

Tsja, deze vier velden naast elkaar in een tabel zou ik direct "slecht ontwerp" noemen. Dit is namelijk tegen de regels van de eerste normaalvorm. Beter zou zijn ze in een aparte tabel te zetten, en dan zou je gewoon een GROUP BY en een MAX() functie kunnen gebruiken.

In een view is het minder erg - zolang die view voor de eindgebruiker bedoeld is. Voor een view waar je later zelf weer verder op manipuleert gelden eigenlijk dezelfde normalisatieregels als voor tabellen.

Jouw idee van een cursor is echt slecht. Cursors zijn de nummer één performance killer in SQL Server. Er zíjn wel situaties waarin je ze kan gebruiken, maar die zijn erg zeldzaam. Eigenlijk zouden cursors in Books Online moeten worden aangemerkt als "very advancced - to be used only by experts"; niet omdat ze zo ingewikkeld zijn, maar omdat alleen een expert kan inschatten wanneer er écht geen betere oplossing is. De praktijk is echter dat ze heeel veel worden gebruikt, vooral door mensen met weinig database ervaring omdat werken met een cursor heel erg lijkt op hun ervaring met 3GL of OO talen, terwijl set-based queries een heel andere manier van denken vereisen.

Tenslotte ook nog een oplossing (daarvoor kom je hier, tenslotte). Twee zelfs. Als je alleen een sleutelveld en het maximum wilt hebben, dan kan je het volgende gebruiken:

<span style="font-family: monospace;">SELECT Sleutel, MAX(Waarde) AS MaxWaarde<br />
FROM (SELECT Sleutel, Waarde1 AS Waarde<br />
&#160;&#160;&#160;&#160;&#160; FROM&#160;&#160; JouwView<br />
&#160;&#160;&#160;&#160;&#160; UNION ALL<br />
&#160;&#160;&#160;&#160;&#160; SELECT Sleutel, Waarde2 AS Waarde<br />
&#160;&#160;&#160;&#160;&#160; FROM&#160;&#160; JouwView<br />
&#160;&#160;&#160;&#160;&#160; UNION ALL<br />
&#160;&#160;&#160;&#160;&#160; SELECT Sleutel, Waarde3 AS Waarde<br />
&#160;&#160;&#160;&#160;&#160; FROM&#160;&#160; JouwView<br />
&#160;&#160;&#160;&#160;&#160; UNION ALL<br />
&#160;&#160;&#160;&#160;&#160; SELECT Sleutel, Waarde4 AS Waarde<br />
&#160;&#160;&#160;&#160;&#160; FROM&#160;&#160; JouwView) AS d<br />
GROUP BY Sleutel;<br />
</span>

Als je nog meer kolommen in het resultaat wilt hebben, dan is deze constructie niet mogelijk. In dat geval zit je vast aan een tamelijk ingewikkelde CASE:

SELECT Sleutel, --andere kolommen hier toevoegen,<br />
&#160;&#160;&#160;&#160;&#160;&#160; CASE WHEN Waarde1 >= COALESCE(Waarde2, Waarde1)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND Waarde1 >= COALESCE(Waarde3, Waarde1)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND Waarde1 >= COALESCE(Waarde4, Waarde1) THEN Waarde1<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN Waarde2 >= COALESCE(Waarde3, Waarde2)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; AND Waarde2 >= COALESCE(Waarde4, Waarde2) THEN Waarde2<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WHEN Waarde3 >= COALESCE(Waarde4, Waarde3) THEN Waarde3<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ELSE Waarde4<br />
&#160;&#160;&#160;&#160;&#160;&#160; END AS MaxWaarde<br />
FROM&#160;&#160; JouwView;


Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
Hugo KornelisUser is Offline

Posts:19

27-01-2010 10:01:44 Alert 
Wow, dat ging niet helemaal goed met de opmaak....

Nogmaals:
de eerste query:
SELECT Sleutel, MAX(Waarde) AS MaxWaarde
FROM (SELECT Sleutel, Waarde1 AS Waarde
FROM JouwView
UNION ALL
SELECT Sleutel, Waarde2 AS Waarde
FROM JouwView
UNION ALL
SELECT Sleutel, Waarde3 AS Waarde
FROM JouwView
UNION ALL
SELECT Sleutel, Waarde4 AS Waarde
FROM JouwView) AS d
GROUP BY Sleutel;

De tweede query:
SELECT Sleutel, --andere kolommen hier toevoegen,
CASE WHEN Waarde1 >= COALESCE(Waarde2, Waarde1)
AND Waarde1 >= COALESCE(Waarde3, Waarde1)
AND Waarde1 >= COALESCE(Waarde4, Waarde1) THEN Waarde1
WHEN Waarde2 >= COALESCE(Waarde3, Waarde2)
AND Waarde2 >= COALESCE(Waarde4, Waarde2) THEN Waarde2
WHEN Waarde3 >= COALESCE(Waarde4, Waarde3) THEN Waarde3
ELSE Waarde4
END AS MaxWaarde
FROM JouwView;

En de optie die Andre noemt (met unpivot) is ook een goede.

Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
Stephan BussingUser is Offline

Posts:54

27-01-2010 12:30:22 Alert 
Hugo en Andre, bedankt voor jullie reacties.

ik ben het met je eens dat het DB ontwerp beter kan (als jet het ontwerp zou zien, dan zou je nog meer commentaar hebben), maar ik zit hiermee vast aan het ontwerp wat door de klant is aangeleverd en die wil dit zou houden. Prima, ik ga er we omheen. Daarom ook de vraag.

Ik ken beide oplossingen niet, maar ik ga het proberen. Beide oplossing. Geweldig. Bedankt.
Stephan BussingUser is Offline

Posts:54

27-01-2010 14:54:57 Alert 
@Andre,

Begrijp ik het goed dat ik de uitkomst van die view (uit jouw voorbeeld) moet combineren met mijn view? Ik bedoel ik kan uit jouw view met Max bepalen wat de hoogte waarde is voor elke unieke Id. Heb ik jou zo goed begrepen. Het pivot verhaal is nieuw voor mij, en ik wil het graag begrijpen.

@Hugo,

Het Case-statement werkt prima. Alleen moets ik wel iets anders te werk gaan omdat de kolommen die gebruikt worden (Waarde1....etc) het resultaat waren van select-statements in de view. Die kan ik dus niet rechtstreeks gebruiken. Tenminste ik kreeg daar een fout op. Ik heb daarom het resultaat van de view in een temp-table gedumpt en daar het Case-statement aan toe gevoegd. Ging prima. Als dat niet de goede werkwijze is hoor ik het natuurlijk graag.

Thx
André KammanUser is Offline
PASS Nederland

Posts:124


27-01-2010 15:28:25 Alert 
Inderdaad, mijn voorbeeld view kan de gegevens uit jouw view "kantelen" zodat je zelf weer mijn view kunt aanroepen en er bijvoorbeeld een max overheen gooien.
Dit maakt het flexibel, je kunt nu zelf bepalen of je een max over het geheel wilt, of per setje antwoorden etc.
Hugo KornelisUser is Offline

Posts:19

27-01-2010 15:32:12 Alert 
Hoi Stephan,

Ik begrijp niet zo goed wat je bedoelt. Als de view die jij hebt een gewone, "standaard" view is (dus met CREATE VIEW gemaakt) waar de vier kolommen Waarde1 t/m Waarde4 in voorkomen, dan zou mijn query gewoon moeten werken (mits je "JouwView" vervangt door de echte naam van je view, uiteraard)

Misschien moet je anders iets meer informatie geven over die bestaande view?

Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
Stephan BussingUser is Offline

Posts:54

27-01-2010 16:43:41 Alert 
@Andre, bedankt. Ik had dat vermoeden al.

@Hugo, nou het is niet echt een standaard view. Idd een aantal velden heb ik gewoon bij elkaar kunnen slepen, maar de velden waarde waardes in staan die ik nodig heb, heb ik er via een select-statement bij gezet.

vb.: select field1,field2,(select waarde from x) as waarde1, etc.. Het veld Waarde1 kon ik niet rechtstreeks gebruiken in jouw voorbeeld (daar kreeg ik een foutmelding op), vandaar mijn opmerking. Het werkt allemaal prima en zal beste beter kunnen, maar ik dit is genoeg om een rapport te bouwen.
Hugo KornelisUser is Offline

Posts:19

28-01-2010 13:23:47 Alert 
Hoi Stephan,

Mijn query zou gewoonmoeten werken als je de view echt als view in SQL Server hebt gemaakt. Dus zoiets als (opmaak probeer ik niet meer...)

CREATE VIEW JouwView
AS SELECT field1, field2, (SELECT waarde FROM x) AS waarde1, etc
FROM etc;
GO

Na uitvoeren van dit statement bestaat een view met de naam JouwView die je gewoon in elke query kan gebruiken - dus ook in degene die ik gaf.

Maar ik krijg de indruk dat jij dit als query hebt, ergens opgeslagen of ingebed in een front end programma, en dat je zoekt naar een manier om bv een extra kolom toe te voegen met het maximum van de vier waarde-kolommen. En dan kan je inderdaad niet in de formule voor die extra kolom verwijzen naar de aliassen van andere kolommen uit dezelfde SELECT. Daar zijn wel andere oplossingen voor. Deze werkt vanaf SQL Server 2005:

WITH Tussenstap
AS (SELECT field1, field2, (SELECT waarde FROM x) AS waarde1, etc
FROM etc)
SELECT field1, field2, waarde1, waarde2, waarde1 + waarde2
FROM Tussenstap;

(Ik gebruik hier "waarde1 + waarde2" als formuler omdat mijn post te groot zou worden als ik de complete formule die ik eerder gaf zou herhalen)

Onderstaande versie is naar mijn mening iets minder duidelijk te lezen, maar werkt ook op versies voor SQL Server 2005:

WITH Tussenstap
AS (SELECT field1, field2, (SELECT waarde FROM x) AS waarde1, etc
FROM etc)
SELECT field1, field2, waarde1, waarde2, waarde1 + waarde2
FROM (SELECT field1, field2, (SELECT waarde FROM x) AS waarde1, etc
FROM etc) AS Tussenstap;

Groetjes, Hugo

Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
André KammanUser is Offline
PASS Nederland

Posts:124


28-01-2010 13:33:12 Alert 
Off Topic :

Hugo, de slechte ondersteuning in dit forum voor voorbeeld code en andere opmaak is een ergernis die mij ook is opgevallen.
Wordt vervolgd....

Groeten,

André
You are not authorized to post a reply.
Forums > Forums > Ontwikkelen > Max value van meerdere velden bepalen



ActiveForums 3.6
  
Copyright (c) 2010 PASS Nederland   Privacy Statement  Terms Of Use