» »

T-SQL FIRST / TOP / MAX...

T-SQL FIRST / TOP / MAX...

nurmaln ::

Imam sledeč problemčič:

Artikel | Line No. | Text
000001 | 1 | Opis 1
000001 | 2 | Opis 2
000001 | 4 | Opis 3
000001 | 7 | Opis 4
000002 | 1 | Opis 1
000002 | 4 | Opis 2
000002 | 8 | Opis 3
000002 | 22 | Opis 4


Za izpis opisov posameznega artikla dam pač SELECT... WHERE Artikel = 000001 ORDER BY Line No

Potreboval bi pa izpis:

Artikel | Opis 1 | Opis 2 | Opis 3 |...

kakšna ideja?

Pudaril bi rad samo dejstvo, da Line No_ si sicer sledijo od njmanjšega do največjega ampak vmes je lahko večja razlika kot samo 1 (prikazano tudi zgoraj)

zigi ::

Ti bi rad dobil ven toliko stolpcev kot je različnih opisov, ali bi rad dal vse opise za določen artikel v en stolpec skupaj?

nurmaln ::

Pravzaprav bi mi koristili obe varjanti. Ampak če jih spravim v ločene stolpce, jih potem ni poseben problem še združiti v enega.

Microsoft ::

Hm, ce bo pomagalo:

SELECT DISTINCT [Text] FROM dbo.Table WHERE [Artikel] = '00000001'

Sicer je pa obracanje s PIVOT funkcijo malo tezje, ker aggregate functions ne delajo najbolje na stringu...


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

kopernik ::

Opisano težavo bi jaz rešil kar v aplikaciji in ne s poizvedbo na bazo (najbrž bi moral napisati kar stored proceduro, ker ne vem če je rešitev možna s standardnim sql). Se pravi, da bi naredil iteracijo čez rezultate in "ročno" zložil vse tekste v enega.

zigi ::

Dosti ljudi pravi 'cursors are bad for you', tu pa imaš primer vgnezdenega kurzorja :P

Recimo da imaš tabelo _tabela(artikel, naziv). Rezultat pa dobiš v tabeli ##temp.
if exists (select 1 from tempdb..sysobjects where name = '##temp')
	drop table ##temp
go
create table ##temp (artikel varchar(16))
go

--tukaj dobiš največje število opisov, da lahko dodaš ustrezno število stolpcev svoji novi tabeli
declare @stOpisov int

select @stOpisov = max(stOpisov)
from (
	select distinct artikel, count(1) stOpisov
	from _tabela
	group by artikel
) k

declare @i int, @imeStolpca sysname, @ukaz varchar(1024)
set @i = 1

while @i <= @stOpisov
begin
	set @imeStolpca = 'Opis' + convert(varchar, @i)
	set @ukaz = 'alter table ##temp add ' + @imeStolpca + ' varchar(255)'
	exec(@ukaz)
	set @i = @i + 1
end

insert into ##temp (artikel) select distinct artikel from _tabela order by artikel


--ko imaš narejeno novo tabelo, vneseš podatke
declare @artikel varchar(16), @naziv varchar(40), @artikelStari varchar(16)
set @i = 0
set @artikelStari = (select top 1 artikel from _tabela order by artikel)

declare c cursor local fast_forward for
	select distinct artikel
	from _tabela
	order by artikel

open c
fetch next from c into @artikel

while @@fetch_status = 0
begin

	declare d cursor local fast_forward for
		select naziv 
		from _tabela 
		where artikel = @artikel 
		order by naziv

  open d
	fetch next from d into @naziv

	while @@fetch_status = 0
	begin
		if @artikel <> @artikelStari
			set @i = 1
		else 
			set @i = @i + 1

		set @imeStolpca = 'Opis' + convert(varchar, @i)
		set @ukaz = 'update ##temp set ' + @imeStolpca + ' = ''' + @naziv + ''' where artikel = ''' + @artikel + ''''
		exec(@ukaz)

		set @artikelStari = @artikel
		fetch next from d into @naziv
	end

	close d
	deallocate d

	fetch next from c into @artikel
end

close c
deallocate c

Zgodovina sprememb…

  • spremenil: zigi ()

frudi ::

Ali je število opisov enako pri vseh artiklih? V tem primeru bi lahko uporabil dosti enostavnejšo rešitev. Ampak predvidevam, da ni, sicer bi imel tabelo s stolpci Text1, Text2, Text3.
Se pa sicer strinjam s kopernikom - takšne probleme, če je le možno, raje rešuj v aplikaciji, ne na bazi.

Če pa že hočeš po vsej sili to počet na bazi, pa je tule še ena rešitev brez kurzorjev. Sicer vsebuje eno WHILE zanko, ampak ta vsaj vsebuje le toliko korakov, kolikor je max. število opisov za posamezni artikel. Ta rešitev je tudi brez dinamičnih SQL stavkov in globalnih začasnih tabel, tako da se procedura ne bi smela vedno znova prevajat ob klicu. Dobiš pa na koncu že sestavljen opis za posamezni artikel. Če bi želel vsak opis v svojem stolpcu, je potrebna še kr precejšnja sprememba. Povej, če to nujno potrebuješ, pa se mogoče spravim dodat še to...
-- začasna tabela za rezultat
IF EXISTS(SELECT * FROM tempdb.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '#ArtTemp%')
	DROP TABLE #ArtTemp

CREATE TABLE #ArtTemp(
	Artikel NVARCHAR(8) NOT NULL,
	[Line No.] INT NOT NULL,
	[Text] NVARCHAR(100) NULL)

-- v začasno tabelo shranimo Artikle in njihov najmanjši Line No.
INSERT INTO #ArtTemp (Artikel, [Line No.])
	SELECT	Artikel, MIN([Line No.])
	FROM	_tabela
	GROUP BY Artikel

-- v začasno tabelo dodamo še 1. opis
UPDATE	#ArtTemp
SET	#ArtTemp.[Text] = A.[Text]
FROM	_tabela AS A
WHERE	#ArtTemp.Artikel = A.Artikel AND #ArtTemp.[Line No.] = A.[Line No.]

-- spremenljivki za iteracijo
DECLARE @i INT
DECLARE @colCount INT

-- max število opisov za posamezni artikel 
SET @i = 1
SELECT	@colCount = MAX(OPIS_COUNT)
FROM	(SELECT Artikel, COUNT([Text]) AS OPIS_COUNT FROM _tabela GROUP BY Artikel) AS X

-- prištejmo še ostale opise...
WHILE @i < @colCount BEGIN
	-- najprej označimo tiste artikle, ki eventualno več nimajo nobenega opisa (nastavimo jim Line No. na -1; lahko bi tudi drugače...)
	-- to preverimo tako, da preverimo, če obstaja še kak zapis z enakim Artikel in večjim Line No.
	UPDATE	#ArtTemp
	SET	#ArtTemp.[Line No.] = -1
	WHERE	NOT EXISTS(
				SELECT	NULL
				FROM	_tabela AS A
				WHERE	#ArtTemp.Artikel = A.Artikel AND #ArtTemp.[Line No.] < A.[Line No.])

	-- Line No. v začasni tabeli postavimo na naslednji najnižji Line No. izmed preostalih zapisov
	UPDATE	#ArtTemp
	SET #ArtTemp.[Line No.] = X.MIN_LINE_NO
	FROM	(SELECT	Artikel, MIN([Line No.]) AS MIN_LINE_NO
			FROM	_tabela AS A
			WHERE	NOT EXISTS(	-- tale pogoj izloči že dodane opise (* skupaj s pogojem za Line No. > -1)
						SELECT	NULL
						FROM	#ArtTemp AS T
						WHERE	A.Artikel = T.Artikel AND A.[Line No.] <= T.[Line No.])
			GROUP BY Artikel) AS X
	WHERE	#ArtTemp.Artikel = X.Artikel AND #ArtTemp.[Line No.] > -1 -- * (glej opombo par vrstic višje...)

	-- v začasno tabelo 'prištejemo' še opise prej določenih naslednjih najnižjih Line No.
	UPDATE	#ArtTemp
	SET	#ArtTemp.[Text] = #ArtTemp.[Text] + ' ' + A.[Text]
	FROM	_tabela AS A
	WHERE	#ArtTemp.Artikel = A.Artikel AND #ArtTemp.[Line No.] = A.[Line No.]

	-- d0h... 
	SET @i = @i + 1
END

-- preverimo rezultat
SELECT	Artikel, [Text]
FROM	#ArtTemp
1ACDoHVj3wn7N4EMpGVU4YGLR9HTfkNhTd... in case I've written something useful :)


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[SQL] Pohitritev izpisa

Oddelek: Programiranje
252902 (1801) kuall
»

PostgreSQL pomoč

Oddelek: Programiranje
162503 (1996) Mato989
»

[SQL] Unikatni izpisi

Oddelek: Programiranje
212218 (1605) 111111111111
»

T-SQL preprost querry pa ne znam

Oddelek: Programiranje
171820 (1477) borchi
»

[delphi] 2 bazi v eni mreži

Oddelek: Programiranje
61103 (1052) seawolf

Več podobnih tem