webForumDet fria alternativet

Besvär med UNION

Databaser & SQL

2 svar · 325 visningar · startad av pulse

Medlem sedan nov. 200373 inlägg
Frågan#1

Hej, har lite problem här med hur jag ska lösa en enorm UNION-fråga. Jag har två tabeller, tabell1 och tabell2.

Tabell1 är min "population" och den innehåller kategori och nivå. Kategori kopplas samman med tabell2 och nivå är ett värde som kan vara antingen niv1, niv2 eller niv3.

Tabell1

Kategori int
Nivå varchar(4)

Tabell2 är en temptabell och jag har fyllt den med alla giltiga kategorivärden, dvs 10, 20...

Tabell2

Kategori int
Beskrivning varchar(250)

Förväntat resultat är:

Kategori	niv1	niv2	niv3	Summa
10		1	2	1	4
20		3	2	1	6
Special		2	2	3	7
Ogiltiga	0	1	0	1
Summa		6	6	5	18

Lite förklaringar:

Kategori = 10, niv = niv1
10/niv1 ökar ett steg

Kategori = a, niv = niv2
Special/niv2 ökar ett steg

Kategori = a, niv = niv3
Special/niv3 ökar ett steg

Kategori = '', niv = niv3
Ogiltiga/niv3 ökar ett steg

Kategori = 'dasdsa', niv = niv3
Ogiltiga/niv3 ökar ett steg

"Kategori a" är ett "specialvärde" (egentligen ett utryck) och jag kan inte lägga in den i tabell2. Den beräknas på annat sätt.
Är inte kategori 10, 20, eller "a" vill jag att ogiltiga ska öka ett steg. Så jag gissar det blir nån slags if, else if, else variant men jag har ingen aning om hur man skriver det i SQL.

I min nuvarande kod använder jag union men det känns inte direkt optimalt och jag får repetera samma saker hela tiden.

create table #a
--fyll med giltiga kategorivärden
--giltiga kategorier
select #a.beskrivning,
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv1',
sum(case when t.niv = "niv2" then 1 else 0 end) as 'niv2',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv3',
count(case when t.niv is not null then 1 end) as 'summa'
from #a left join tabell t on t.kategori = #a.kategori

union all

--special kategorier
select 'Special',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv1',
sum(case when t.niv = "niv2" then 1 else 0 end) as 'niv2',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv3',
count(case when t.niv is not null then 1 end) as 'summa'
tabell t where t.kategori = 'a'
and namn = "kalle" --namn = "kalle" finns bara här på special-kategorier

union all

--ogiltiga kategorier
select 'Ogiltiga',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv1',
sum(case when t.niv = "niv2" then 1 else 0 end) as 'niv2',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv3',
count(case when t.niv is not null then 1 end) as 'summa'
from tabell t where t.kategori not in (select kategori from #a)
or !(t.kategori = 'a' and t.namn = 'kalle') --här är jag inte säker på om det bli rätt heller

union all

--summa --summa ska räkna allting, giltiga, special eller ogiltiga kategorier
select 'Summa',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv1',
sum(case when t.niv = "niv2" then 1 else 0 end) as 'niv2',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv3',
count(case when t.niv is not null then 1 end) as 'summa'
from tabell t

Blev långt det här men jag hoppas ni förstår mitt problem. Finns det något sätt att komma undan UNION eller är det här det enda sättet att lösa det på? Den verkliga SQL-satsen är nästan 500rader kod och helt omöjlig att hantera! t.niv = "niv1" then 1 else 0 end... återkommer hela tiden, finns det smart sätt att återanvända just den biten åtminstonde?

Medlem sedan dec. 19996 721 inlägg
#2

pulse skrev:

Tabell1

Kategori int
Nivå varchar(4)

I din SQL-fråga verkar det inte som att Kategori är "int". Nä int verkar det så int.

pulse skrev:

"Kategori a" är ett "specialvärde" (egentligen ett utryck) och jag kan inte lägga in den i tabell2. Den beräknas på annat sätt.

Varför? I din SQL-fråga har du använt den som att det skulle fungera med att ha den i temptabellen.

INSERT INTO #a (Kategori,Beskrivning,Sortering) VALUES('','Ogiltig',1)
INSERT INTO #a (Kategori,Beskrivning,Sortering) VALUES(NULL,'Summa',2)

SELECT #a.Beskrivning, 
sum(case when t.niv = 'niv1' then 1 else 0 end) as 'niv1',
sum(case when t.niv = 'niv2' then 1 else 0 end) as 'niv2',
sum(case when t.niv = 'niv3' then 1 else 0 end) as 'niv3',
sum(1) as 'summa'
FROM #a
LEFT JOIN tabell t on #a.Kategori IS NULL OR #a.Kategori=t.Kategori OR (#a.Kategori='' AND t.kategori NOT IN (SELECT kategori FROM #a WHERE Kategori<>''))
GROUP BY #a.Beskrivning
Medlem sedan nov. 200373 inlägg
#3

Hej och tack för svaret. Nej jag har slarvat lite och inte skrivit av (förenklat) frågan exakt som den ser ut på min Sql-dator. Min tanke var att #a bara ska innehålla giltiga värden på kategorier (10, 20, 30, 40...) aldrig 'a' som är ett specialfall.

tabell t where t.kategori = 'a'

Det här blir då lite missvisande. Mitt specialfall kanske borde ha sett ut såhär istället:

--special kategorier
select 'Special',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv1',
sum(case when t.niv = "niv2" then 1 else 0 end) as 'niv2',
sum(case when t.niv = "niv1" then 1 else 0 end) as 'niv3',
count(case when t.niv is not null then 1 end) as 'summa'
tabell t where namn = "kalle" --namn = "kalle" finns bara här på special-kategorier

Jag vill alltså att alla poster som uppfyller ett visst krav (namn = "Kalle") ska hamna under kategorin "Special". Uppfyller samma post kravet på ett giltigt kategorivärde så hamnar den också på giltiga kategorier så samma post kan räknas flera gånger.

Jag vore också tacksam om du kunde ta dig tid med en liten förklaring av din kod och hur den ska tillämpas på mitt problem.

Problemet är alltså hur jag får ut den här tabellen:

Kategori	niv1	niv2	niv3	Summa
10		1	2	1	4
20		3	2	1	6
Special		2	2	3	7
Ogiltiga	0	1	0	1
Summa		6	6	5	18

...på enklast möjliga sätt. Jag har beskrivit hur jag beräknar kategori 10, 20, Special, Ogiltig och Summa. sum(case when niv="1" then 1 else 0 end) -biten återkommer hela tiden, kan man inte utnyttja det på något sätt så att det blir iaf lite mindre kod?

253 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
120 ms — deklarationer (db)
0 ms — hämta statistik (cache)
130 ms — hämta tråd, inlägg och bilagor (db)
118 ms — ändringar (db)