Har ett litet delikat problem. Egentligen är det väl inte så att jag inte kan lösa det, men alla lösningar känns "fel". Det kan bero på hur problemet är betingat. Jag kan ju börja med att säga att jag har fått komma in mitt i ett system här. Det är nog ganska svårt att både förklara och förstå, men jag ska göra ett försök: Jag gissar att du är ute efter att konvertera rader till kolumner, alltså pivotera? Det kan vara lite klurigt, speciellt om samma kod ska funka mot Access/SQL server/Oracle. Lycka till :) Mmm... "ungefär". Det är snarare så att vissa specifika rader i en tabell ska motsvara vissa specifika kolumner i en annan. Alltså ingen generellare variant. Vilken är anledningen till att du vill ha ut resultatet på den formen? Skulle det inte fungera med ett annat format som dock kräver att du skriver ut det annorlunda? Anledningen är att det är en VBA/Excel-applikation, och jag får då resultatet som en variant-matris. Fortfarande intresserad av din lösning, Per (av ren nyfikenhet, kund mycket nöjd med min lösning). Jag tänkte mig något i den här stilen (pseudokod inspirerad av både PHP och ASP/VBS): Ahaa, det tog ett tag innan jag kopplade. Fast jag vet inte om du har skrivit helt rätt? <b>Du måste väl först garantera att de kommer i rätt ordning?</b>SQL-query åt "fel håll"?
Om jag gör en lite kortare version på hur det är uppbyggt har jag två tabeller. (Terminologin och namngivningen är inte så exakt här. Jag byter ut namnen.)
projekt och enhet.
De är kopplade till varandra i en n:n-relation, som beskrivs av en kopplingstabell cProjEnhet. (1)
Vidare har vi lite egenskaper för alla enheter. De kan till exempel vara av en viss typ. Dessa typer beskrivs av ytterligare en tabell ("Typ").
Sen har vi en kopplingstabell mellan dessa två (2). cEnhetTyp kan vi låtsas att den kallas.
Nu vill vi ta ut en lista på alla projekt, inget problem:
SELECT id, name, desc, ... FROM Projekt;
(3)
Nu kommer det lite knepiga. Vi vill nu välja ut alla enheter av en viss typ X:
SELECT * FROM (Enheter INNER JOIN cEnhetTyp INNER JOIN Typ) WHERE Typ.Name = "X"
Denna vill vi sen kunna koppla till projekten, och lägga som en kolumn till den frågan. Alltså: Om ett projekt är kopplad till en enhet, som i sin tur har en viss typ, så vill vi lägga den som en av kolumnerna i frågan.
Typ:
SELECT id, name, desc, Enheter.Name FROM
Projekt LEFT JOIN cProjektEnhet LEFT JOIN [frågan ovanför]
Detta funkar hyfsat. Om man bara skriver in frågan däruppe, så väljer vi ju bort alla rader som inte matchas, jag vill ju ha null om det inte finns någon enhet av den typen. Man får väl därför i princip göra en subquery.
Sen ska vi har detta för fyra hårdkodade typer ("X", "Y", "Z", "W"), som ska hamna på var sitt hårdkodade ställe i kolumnordningen. För att klara detta skulle jag ju i så fall behöva göra fyra subqueries, döpa om deras resultat, och sätta ihop hela köret med min övriga fråga.
Det känns fel. Och framför allt känns det som något som riskerar att inte fungera tvärs över databaser. Det enda som är aktuellt just nu är Access och MSSQL, men även Oracle är på tal. Ska subqueries funka i de databaserna?
Är det någon som har något annat förslag?
Vidare vill man helst bara ha en enhet av varje typ för varje rad (det finns ju inget som hindrar att det är flera enheter av samma typ). Det spelar ingen roll vilken (!), i de allra flesta fall finns bara en sådan. Det kan jag i värsta fall lösa via kod.
(1)
Själv skulle jag väl kallat den related eller va fan som helst, men inte cProjEnhet.
(2)
Helt fel, borde varit ett fält i Enhet, men skit samma.
(3)
Vidare ska vi koppla detta till 4 andra tabeller, men det är inte jätterelevant.Sv: SQL-query åt "fel håll"?
Kanske lika bra att du hårdkodar joins för kolumnerna om typerna/kolumnerna ändå är hårdkodade och ej föränderliga. Eller så googlar du http://www.google.se/search?hl=sv&q=select+sql+pivotSv:SQL-query åt "fel håll"?
Har löst det med subqueries nu, så det funkar. Men jag ryser när jag ser lösningen.Sv: SQL-query åt "fel håll"?
Sv:SQL-query åt "fel håll"?
Denna kan jag sedan skriva ut med ett enda anrop till Excel-bladet, typ:
range(cells(x1,y1), cells(x2, y2)) = avntData
Det är inte så att jag inte kan skriva ut det på ett annat sätt, men eftersom jag har en "fungerande lösning" nu så får det vara en ganska mycket bättre lösning för att jag ska byta. Jag genererar kodmässigt fyra delfrågor a' 2 joinar och ytterligare 4 joinar. sqlsatsen tar väl upp ett halvt A4 ungefär. Men det funkar ju...
Jag har för övrigt diskuterat möjligheten med vyer för att åtminstone göra det lite mer överskådligt, men eftersom beställaren inte verkar vilja ha det så skippar vi det.
Större databasändringar kommer inte på fråga.
Hur hade du tänkt Per?Sv: SQL-query åt "fel håll"?
Sv:SQL-query åt "fel håll"?
<code>
sql = "
SELECT Projekt.Namn, Enhet.Namn, Typ.Namn
FROM Projekt
LEFT JOIN (
cProjektEnhet
ON Projekt.Id = cProjektEnhet.ProjektId
INNER JOIN Enhet
ON cProjektEnhet.EnhetId = Enhet.Id
INNER JOIN cEnhetTyp
ON Enhet.Id = cEnhetTyp.EnhetId
INNER JOIN Typ
ON cEnhetTyp.TypId = Typ.Id AND Typ.Namn IN ('X', 'Y', 'Z', 'W')
)
";
res = query(sql);
print '<table>';
print '<tr>';
print '<th>Projekt</th>';
foreach(typnamn in ('X', 'Y', 'Z', 'W'))
{
print '<th>', typnamn, '</th>';
}
print '</tr>';
// getRow() hämtar aktuell rad och flyttar fram radpekaren till nästa rad; ger null om ingen rad finns
row = res.getRow();
while(row != null)
{
print '<tr>';
print '<td>', row['Projekt.Namn'], '</td>';
foreach(typnamn in ('X', 'Y', 'Z', 'W'))
{
if(row['Typ.Namn'] != null)
{
print '<td>', row['Enhet.Namn'], '</td>';
row = res.getRow();
}
else
{
print '<td> </td>';
}
}
print '</tr>';
}
print '</table>';
</code>Sv: SQL-query åt "fel håll"?
Du måste väl först garantera att de kommer i rätt ordning?
Och hur vet du att det kommer finnas motsvarande en rad per typ, du kör ju med inner-joinar?
Jag antar att du har tänkt igenom det.
Lösningen är ändå tyvärr bara hyfsad i den miljön jag sitter i.
Grejen är att företaget har något eget interface mot databasen, vilket innebär att jag inte kan få någon cursor överhuvudtaget, jag får en s k variant-array.
Det jag då i princip skulle kunna göra är att loopa igenom denna och justera varje rad. Problemet som då uppstår är att jag har en ful extrakolumn som inte är helt lätt att få bort i VBA. Tar jag inte bort den hamnar den i Excelarket, vilket nästan är lika illa.
Dessutom tar din just nu inte hand om dubbla rader.
Just nu är koden typ:
<code>
sql = " SELECT ..."
'Massa meckande med att skapa en sql-sats
data = clsdb.getsql(sql)
worksheet.cell(x,y) = data
</code>
Med din hade det blivit något i stil med:
<code>
sql = "SELECT ..."
data = clsdb.getsql(sql)
for i = lbound(data, 1) to ubound(data, 1)
for j = lbound(data, 2) to ubound(data, 2) "utom aktuella kolumner"
temp(i, j) = data(i, j)
next j
for j = 1 to 4
if data(i, col1) = Typ(4) then temp(i, col2) = data(i, col3)
next j
next i
'Ta bort data, lägg över arrayen från temp till data
skriv ner data från tidigare
</code>
Din lösning är bra Per, men den funkar tyvärr inget vidare i mitt fall.Sv:SQL-query åt "fel håll"?
Javisst, och det har jag glömt.
<b>Och hur vet du att det kommer finnas motsvarande en rad per typ, du kör ju med inner-joinar?</b>
En LEFT JOIN finns (den första joinen). En eller ingen rad per typ går bra, däremot inte flera. Men koden behöver nog inte modifieras särskilt mycket för att fungera om det kan förekomma flera rader.
<b>Lösningen är ändå tyvärr bara hyfsad i den miljön jag sitter i.</b>
Min lösning är inte avsedd för din miljö eftersom jag inte visste särskilt mycket om den tidigare. Som synes är den mer avsedd för webbutveckling.