• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[MSSQL] Query mit dynamischer Spaltenselection

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
Servus zusammen,
habe mal ein evtl. auch für den ein oder anderen interessantes Problem ;)

Ausgangslage:
Ich habe eine vorgegebene Tabellenstruktur einer CMDB (Struktur-Beispiel weiter unten)
Jedes CI kann dabei eine freie Anzahl von Eigenschaften annehmen und den Wert zu diesen Eigenschaften speichern.
Zusätzlich können weitere Eigenschaften für Ci's erstellt werden.

Ziel:
Die Ausgabe einer Tabelle mit allen Ci's und ihren jeweiligen Eigenschaften + Werten.
z.B. bei einem Computer + einem Monitor als Ausgabe:

Name, CPU, Ram. Größe(zoll), Display
pc1, 2, 2, null, null
tft1, null, null, 24, LED

Da die Anzahl der Eigenschaften und somit die Anzahl der Spalten sich jederzeit (und je nach selektion der Ci's z.B. nach Namen) ändern kann - müssen die Spalten Dynamisch generiert werden.

Aktueller Stand:

Aktuell habe ich einen Query der keinen Syntax-Error erzeugt :T und, insofern nur ein Eintrag in der Tabelle für Attributs-Verknüpfungen steht - auch genau das richtige Ergebnis angezeigt wird (Im Beispiel it_cmdb_ci_attr)
Insofern dort aber mehrere Einträge erstellt werden - werden die ausgegebenen Einträge zum ² mehr ... das heißt irgendwo habe ich eine Schleife drin - oder eine Begrenzung fehlt.
Ich bin hier nun leider mit meinem Latein am Ende - und weiß im Moment auch nicht wie ich den Query so Debuggen kann das ich verstehe wo der Fehler ist.

Damit man sich das ganze besser vorstellen kann habe ich ein Demoszenario erstellt das in einer leeren DB alles passende anlegt. Am Ende Steht die Query

Beispiel (MSSQL!):
[src=mysql]CREATE TABLE [dbo].[it_cmdb_ci_attr](
[cmdb_ci_attr_id] [int] NOT NULL,
[change_id] [int] NULL,
[cmdb_ci_id] [int] NULL,
[cmdb_product_attr_id] [int] NULL,
[content] [varchar](512) NULL,
[product_id] [int] NULL,
[im_attr_id] [int] NULL,
[immediate_update] [char](1) NULL,
CONSTRAINT [PK_it_cmdb_ci_attr] PRIMARY KEY CLUSTERED
(
[cmdb_ci_attr_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO


CREATE TABLE [dbo].[it_product_label](
[product_label_id] [int] NOT NULL,
[data_type] [varchar](15) NULL,
[label_active] [char](1) NULL,
[product_label] [varchar](25) NULL,
[product_label_type] [varchar](25) NULL,
[immediate_update] [char](1) NULL,
CONSTRAINT [PK_it_product_label] PRIMARY KEY CLUSTERED
(
[product_label_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


GO


CREATE TABLE [dbo].[it_cmdb_product_attr](
[cmdb_product_attr_id] [int] NOT NULL,
[label_from] [varchar](20) NULL,
[label_to] [varchar](20) NULL,
[mandatory] [char](1) NULL,
[product_id] [int] NULL,
[product_label_id] [int] NULL,
[importkey] [varchar](200) NULL,
CONSTRAINT [PK_it_cmdb_product_attr] PRIMARY KEY CLUSTERED
(
[cmdb_product_attr_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


Go


INSERT INTO [dbo].[it_cmdb_product_attr]
([cmdb_product_attr_id] ,
[label_from],
[label_to] ,
[mandatory],
[product_id],
[product_label_id],
[importkey])
VALUES
(11081,NULL,NULL,'Y',10336,10001,'Beamer-Modell')
GO


INSERT INTO [dbo].[it_product_label]
( [product_label_id],
[data_type] ,
[label_active] ,
[product_label] ,
[product_label_type] ,
[immediate_update])
VALUES
(10001,'Text','Y','Modell','Hardware',NULL)
GO


INSERT INTO [dbo].[it_cmdb_ci_attr]
( [cmdb_ci_attr_id] ,
[change_id] ,
[cmdb_ci_id] ,
[cmdb_product_attr_id] ,
[content] ,
[product_id],
[im_attr_id] ,
[immediate_update])
VALUES
(177718,NULL,61910,11081,'CY9400DBXMP',10347,NULL,NULL)
GO








DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)


select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Product_label)
from it_product_label
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')


set @query = 'select it_cmdb_ci_attr.cmdb_ci_id, ' + @cols + ' from
it_product_label,it_cmdb_ci_attr, (
select it_cmdb_ci_attr.cmdb_ci_id, it_product_label.product_label, it_product_label.product_label_type, it_cmdb_ci_attr.content
from it_cmdb_ci_attr
left join it_cmdb_product_attr on it_cmdb_product_attr.cmdb_product_attr_id = it_cmdb_ci_attr.cmdb_product_attr_id
left join it_product_label on it_cmdb_product_attr.product_label_id = it_product_label.product_label_id
) x
pivot
(
min(content)
for Product_label in (' + @cols + ')
) p '


execute(@query)
[/src]
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Da die Anzahl der Eigenschaften und somit die Anzahl der Spalten sich jederzeit (und je nach selektion der Ci's z.B. nach Namen) ändern kann - müssen die Spalten Dynamisch generiert werden.
Meines Erachtens nach ist das Problem auf der DB Design Ebene zu verorten.
Erster Ansatz wäre ein Auslagern der Eigenschaften in eine eigene Tabelle. Spalten: id, name, wert

Am besten du gibst hier im Thread erstmal deine DB Struktur nieder. Ich habe den Eindruck dass du einfach nur an eine einzelne Tabelle denkst.
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
  • Thread Starter Thread Starter
  • #3
öhm - die DB-Struktur, bzw. der relevante Teil ist im Beispiel mit drin... und an der Struktur kann ich nichts ändern...
 

ElricM

Core Quäler

Registriert
14 Juli 2013
Beiträge
2.034
Hallo DrFuture,

auch auf die Gefahr hin, dass ich nun Prügel bekomme. Aber select distincts und dynamisches SQL sind aus Performancegründen pfui. Sagt Dir Full-Table-Scan etwas ? Den Optimizer der Datenbank kannst Du bei solchen Abfragen auch vergessen.
Solche Logik kommt heute nicht mehr in die Datenbank. Ich kämpfe seit Jahren in diversen Projekten um die Ablöse solcher Ansätze. Kommst Du aus der C#-Ecke ? PLINQ und EF wären hier prima.

Grüße
ElricM
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
  • Thread Starter Thread Starter
  • #5
Ach was Haue bekommt von mir keiner ;D
Aber in dem Fall geht mehr oder weniger "nur" eine solche Abfrage... da eben die Datenbankstruktur vorgegeben ist und das Ergebnis eine View sein muss die dann weiter verwendet wird. Die Abfrage wird max. 1x im Monat ausgeführt von 1-2 Personen... die Last ist damit zu vernachlässigen...
Das das nicht sonderlich Performant ist weiß ich schon.. in dem Fall geht Nutzbarkeit für die Zielgruppe über die Performance... da die Benutzer im obersten Stockwerk sitzen *fg*
 
Oben