Overblog
Folge diesem Blog Administration + Create my blog
Blog von Olaf Helper
Neueste Posts

SSMS 2008 R2 IntelliSense nach VS 2010 SP 1

13. März 2011 , Geschrieben von Olaf Helper Veröffentlicht in #MSSQL

Ich hatte es ich letzten Blog Artikel bereits erwähnt, das erste Probleme im Zusammenhang mit dem Microsoft Visual Studio 2010 Service Pack 1 gemeldet wurden.

Einer muss ja Versuchskaninchen sein und deshalb habe ich mal auf meinem Rechner das Service Pack 1 installiert; zu updaten gab es MS Visual Basic 2010 Express Edition, MS C# 2010 Express Edition und MS Visual Web Developer 2010 Express Edition, sowie diverse Redistributables. Die Installation per WebInstaller lief gut eine Stunde und das völlig reibungsfrei ab.

Erste tests im SSMS 2008 R2 ergaben nun: Tabellen, Views, Stored Procedures und Funktionen werden weiterhin von IntelliSense aufgelistet, aber keine Feldnamen mehr. Parameterinfo funktioniert ebenfalls wie gehabt.

Vor der Installation des SP 1 sollte man aich also zunächst überlegen, ob man mit der Einschränkung leben kann. Ein Komfort-Verlust ist es, aber meines Erachtens auch nicht so tragisch.

Weiterlesen

Visual Studio 2010 Service Pack 1 ... aber bitte mit Vorsicht

10. März 2011 , Geschrieben von Olaf Helper Veröffentlicht in #MSSQL

 

Kürzlich ist das Microsoft Visual Studio 2010 Service Pack 1 erschienen. Grundsätzlich neige ich dazu, Service Packs auch zu installieren, neben Benefits wie Stabilität, Performance und Sicherheit bieten sie manchmal auch neue Features.

 

In diesem Fall ist aber etwas Vorsicht geboten, denn den ersten Rückmeldungen in MSDN Foren wie

SSMS 2008 R2 IntelliSense Stopped Working after VS 2010 SP1

zufolge hat das Service Pack eher negative Auswirkungen auf das SSMS = Sql Server Management Studio; IntelliSense funktioniert anschließend nicht mehr.

 

Das CU6 für Sql Server 2008 R2 soll das Problem beheben. Aber das kann es ja nun eigentlich nicht sein, das man sich mit einem Service Pack sich Probleme einholt, die man mit einem weiteren CU erst wieder beheben muss. 

Weiterlesen

Verlauf der Systemspeichernutzung ermitteln

24. Februar 2011 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Die DMV sys.dm_os_ring_buffers, die mit Microsoft SQL Server Version 2005 eingeführt wurde, gehört zu den wenigen, die offiziell nicht dokumentiert ist und in der BOL zu den DMVs zum Betriebssystem steht „..not supported …only for information … not guaranteed …“. Nun, für Applikationen würde ich die DMV als Informationsquelle nicht verwenden, aber ein Blick schadet nicht, vielleicht liefert sie doch interessante Informationen.

 

Die View selbst ist sehr „flach“, nur 4 Felder:

-       ring_buffer_address varbinary(8): Mit der kann ich noch nichts anfangen

-       ring_buffer_type nvarchar(60): Eine Typebezeichnung in Klartext

-       timestamp bigint: Weder datetime noch rowversion, sondern reine Zahlen

-       record nvarchar(2048): Die Daten sehen aus wie XML, sind nur nicht so deklariert

 

Der Inhalt von „timestamp“ war schnell geklärt, es sind die Ticks (= Millisekunden) seit dem Rechnerneustart, hat also nichts mit @@TIMETICKS zu tun. Über das Feld ms_ticks aus dem DMV sys.dm_os_sys_info kann man den aktuellen Ticks-Stand ermitteln und darüber auf den eigentlichen Zeitpunkt rückrechnen.

Welche Type es (aktuell) gibt, kann mit einer einfachen Abfrage ermitteln:

 

 SELECT ring_buffer_type 
  ,COUNT(*) AS Occured 
 FROM master.sys.dm_os_ring_buffers 
 GROUP BY ring_buffer_type 
 ORDER BY ring_buffer_type 

 

Ergebnis (auf Laptop, der kurz vorher gestartet wurde):

 

ring_buffer_type

Occured

RING_BUFFER_MEMORY_BROKER

6

RING_BUFFER_RESOURCE_MONITOR

1

RING_BUFFER_SCHEDULER

824

RING_BUFFER_SCHEDULER_MONITOR

18

RING_BUFFER_XE_BUFFER_STATE

4

RING_BUFFER_XE_LOG

1

 

Na, das erste, was hier mein Interesse weckt, ist natürlich RING_BUFFER_RESOURCE_MONITOR. Wie schon erwähnt, sehen die Daten in „record“ wie XML aus und in den Datentypen kann man es auch konvertieren. Ein solcher „record“ für einen Resource_Monitor Eintrag sieht so aus:

 

 <Record id="0" type="RING_BUFFER_RESOURCE_MONITOR" time="1261574341"> 
  <ResourceMonitor> 
  <Notification>RESOURCE_MEMPHYSICAL_HIGH</Notification> 
  <IndicatorsProcess>0</IndicatorsProcess> 
  <IndicatorsSystem>1</IndicatorsSystem> 
  <NodeId>0</NodeId> 
  <Effect type="APPLY_LOWPM" state="EFFECT_OFF" reversed="0">0</Effect> 
  <Effect type="APPLY_HIGHPM" state="EFFECT_ON" reversed="0">0</Effect> 
  <Effect type="REVERT_HIGHPM" state="EFFECT_OFF" reversed="0">0</Effect> 
  </ResourceMonitor> 
  <MemoryNode id="0"> 
  <ReservedMemory>1671680</ReservedMemory> 
  <CommittedMemory>16636</CommittedMemory> 
  <SharedMemory>0</SharedMemory> 
  <AWEMemory>0</AWEMemory> 
  <SinglePagesMemory>2496</SinglePagesMemory> 
  <MultiplePagesMemory>10232</MultiplePagesMemory> 
  </MemoryNode> 
  <MemoryRecord> 
  <MemoryUtilization>100</MemoryUtilization> 
  <TotalPhysicalMemory>2086596</TotalPhysicalMemory> 
  <AvailablePhysicalMemory>832044</AvailablePhysicalMemory> 
  <TotalPageFile>4416176</TotalPageFile> 
  <AvailablePageFile>2442676</AvailablePageFile> 
  <TotalVirtualAddressSpace>2097024</TotalVirtualAddressSpace> 
  <AvailableVirtualAddressSpace>326988</AvailableVirtualAddressSpace> 
  <AvailableExtendedVirtualAddressSpace>0</AvailableExtendedVirtualAddressSpace> 
  </MemoryRecord> 
 </Record> 

 

Die Namen der Tags sind wie die aus den Speicher Performance Counters von Windows. XML lässt sich in SQL Server ab 2005 prima abfragen und das machen wir mal.

Auf einem Produktiv-System ausgeführt gibt es einige „RESOURCE_MEMPHYSICAL_HIGH“ Einträge; was für einen Server mit laufenden MS SQL Server aber auch nichts Ungewöhnliches ist.

Aber so kann man mit einfachen Mitteln sein System etwas monitoren und das auch noch rückwirkend.

 

 DECLARE @actualTS BIGINT 
 SET @actualTS = (SELECT ms_ticks FROM sys.dm_os_sys_info) 
 PRINT @actualTS 
   
 SELECT ORB.EventTime 
  ,ORB.Notif 
  ,ORB.AvailPhyMem 
  ,ROUND(CONVERT(float, 100 * AvailPhyMem) / TotalPhyMem, 3) AS PercentAvailable 
  ,ORB.MemUtil 
  ,ORB.ResvMem 
  ,ORB.CommMem 
  ,ORB.recordXml 
 FROM (SELECT DATEADD(s, EventTs, GETDATE()) AS EventTime 
  ,ORB.recordXml.value('(./Record/ResourceMonitor/Notification)[1]', 'varchar(50)') AS Notif 
  ,ORB.recordXml.value('(./Record/MemoryNode/ReservedMemory)[1]', 'int') AS ResvMem 
  ,ORB.recordXml.value('(./Record/MemoryNode/CommittedMemory)[1]', 'int') AS CommMem 
  ,ORB.recordXml.value('(./Record/MemoryRecord/MemoryUtilization)[1]', 'int') AS MemUtil 
  ,ORB.recordXml.value('(./Record/MemoryRecord/TotalPhysicalMemory)[1]', 'int') AS TotalPhyMem 
  ,ORB.recordXml.value('(./Record/MemoryRecord/AvailablePhysicalMemory)[1]', 'int') AS AvailPhyMem 
  ,recordXml 
  FROM (SELECT CONVERT(int, (ORB.timestamp - @actualTS) / 1000) AS EventTs 
  ,CONVERT(xml, record) AS RecordXml 
  FROM master.sys.dm_os_ring_buffers AS ORB 

            WHERE ORB.ring_buffer_type = N'RING_BUFFER_RESOURCE_MONITOR'

            ) AS ORB

      ) AS ORB

ORDER BY EventTime desc

Weiterlesen

BIDS Templates für Reporting Projekte anpassen

22. Februar 2011 , Geschrieben von Olaf Helper Veröffentlicht in #Reporting

Die Microsoft Business Intelligence Developer Studio (BIDS) Standard Vorlagen für Reporting Projekte sind nicht so ganz optimal, wie ich finde. Die Report Vorlage selbst ist im Letter Format mit Inches Angaben und die Textgrößen bei Tablix & Co, die vom Wizard erstellt werden, finde ich etwas sehr groß.

Hinzu kommt, das man im Sinne von Corporate Identity bestimmt Elemente wie Header-Logo oder eine Footer-Zeile mit Standard-Infos immer gleich platziert und die Mühe möchte man sich eigentlich sparen.

Diese Standard Vorlagen kann man aber einfach an seine Vorstellungen anpassen; vorher aber immer eine Sicherheitskopie der Dateien erstellen!

 

 

Report Projekte Vorlage

Die Vorlage für Report Projekte fürs BIDS 2008 findet man in:

%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\ReportProjects\ReportProject.rptproj

 

Die Standard Vorlage ist eher leer und viel zum Anpassen gibt es auch nicht, aber man kann schon mal die Ziel-Url vom verwendeten SSRS angeben; halt all die Konfigurationswerte, die man in den Projekt-Eigenschaften festlegt.

 

<?xml version="1.0"?>
<Project xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">
  <DataSources />
  <Reports />
  <!-- Mein Anpassung -->
  <Configurations>
    <Configuration>
      <Name>Debug</Name>
      <Platform>Win32</Platform>
      <Options>
        <TargetServerURL>http://MeinServer/Reportserver_InstanzenName

        </TargetServerURL>
      </Options>
    </Configuration>
    <Configuration>
      <Name>Release</Name>
      <Platform>Win32</Platform>
      <Options>
        <TargetDataSourceFolder>Datenquellen</TargetDataSourceFolder>
      </Options>
    </Configuration>
  </Configurations>
  <!-- 
Ende Anpassung -->  
</Project>

 

 

Report Vorlage

Liegt in

%ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\ProjectItems\ReportProject\Report.rdl

und ist eine ganz normale RDL Datei, die man entsprechend auch mit BIDS bzw. dem Report Builder 2.0 bearbeiten kann, also kein kryptische XML Bearbeitung.

Hier kann man also schon mal das gewünschte Seitenformat vorgeben, ein Logo einfügen, Seitenfuß festlegen und so weiter. Selbst Custom Code, Assemblies und Classes können hier schon eingefügt werden. Wenn man dann in seinem BIDS Projekt einen neuen Report hinzufügt, wird diese RDL Datei als Vorlage kopiert. Der Report Builder verwendet diese Vorlage nicht, ob und von wo der eine Vorlage zieht, ist mir nicht bekannt, im Internet war auch nichts zu dem Thema auffindbar.

 

 

Styles Vorlage

Die Vorlage für Styles liegt in

%ProgramFiles\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Business Intelligence Wizards\Reports\Styles\de\StyleTemplates.xml

Hier ist also wieder XML Bearbeitung angesagt, da empfiehlt es sich, einen XML Editor zu verwenden.

Am besten ist es, man kopiert einen vorhandenen <StyleTemplate> Block, gibt diesen einen neuen, eindeutigen Namen und bearbeitet dann die Werte.

Die Struktur der Styles wird schnell ersichtlich, man kennt es bereits, wenn man schon per Wizard ein Tablix angelegt hat. Man kann je Verschachtelungstief 1 – 3+ (Group Level) die Formatierung definieren. Dabei kann man alle Properties angeben, die man auch aus BIDS kennt. Man muss nur beachten, das XML immer Case Senstive ist, man muss also Groß-/Kleinschreibung beachten.

Die Vorschaufunktion im Wizard funktioniert zwar nicht mit den selbst definierten Styles, aber das stellt nun wirklich kein Beinbruch dar.

 

Hier mal ein Beispiel, bei dem ich für den Report „Title“ das TextAlign=Center setze:

 

<StyleTemplate Name="Olaf">
  <Label>Olaf</Label>
  <Styles>
    <Style Name="Title">
      <FontFamily>Arial</FontFamily>
      <FontSize>20pt</FontSize>
      <Color>MidnightBlue</Color>
      <FontWeight>Bold</FontWeight>
      <TextAlign>Center</TextAlign>
    </Style>
    <...

 

Weiterlesen

SSAS Objekte per AMO verarbeiten und Verlauf per SessionTrace verfolgen

18. Februar 2011 , Geschrieben von Olaf Helper Veröffentlicht in #OLAP

Einen Microsoft Sql Server Analysis Services (SSAS) Cube und dessen Objekte lässt man im produktiven Betrieb natürlich zeitgesteuert per SSIS Package verarbeiten; da will man nicht wirklich bei „zusehen“.

Während der Entwicklungs- & Designphase eines Cube’s lässt man diesen aus BIDS heraus verarbeiten. Die Daten basieren dabei meist auf Views, die die eigentlichen Daten auf eine repräsentative als auch vertretbare Datenmenge beschränken; schließlich verarbeitet man öfter mal den Cube, um das Ergebnis zu kontrollieren und das soll ja nicht jedes Mal einen halben Arbeitstag in Anspruch nehmen. Der Processing Verlauf wird dabei in BIDS (und auch SSMS) in einem TreeView dargestellt und das bietet einem nicht gerade eine gute und informative Darstellung des Verlaufes.

Andererseits sind die Verlaufsinformationen (mir) wichtig, um von den Test- auf die Produktionsdaten hochrechnen zu können.

AMO bietet die Möglichkeit mit einem .NET Programm oder PowerShell programmatisch einzelne Objekte eines Cubes verarbeiten zu können. Über einen Trace könnte man alle Aktivitäten auf dem Analysis Server nach verfolgen und die der eigenen Session herausfiltern; nicht so ganz einfach. Es geht aber auch wesentlich einfacher, indem man das SessionTrace des AMO Server Objektes verwendet, über das man auch die Verarbeitung der Objekte durchführt. Man setzt eine Variable WithEvents, startet den Trace und kann dann alle Ereignisse Event-gesteuert empfangen. In TraceEventArgs erhält man alle Daten, so wie man sie auch aus dem SQL Profiler kennt.

Es gibt aber kleine Probleme mit ein paar Properties von TraceEventArgs, die könnten durch „Ungenauigkeit“ (alias Bug) in AMO verursacht werden und die gilt es zu umschiffen. Das betrifft zum Beispiel das Property IntegerData. Natürlich und verständlicherweise gibt es nicht bei jedem TraceEvent einen Wert für IntegerData, aber dann würde ich davon ausgehen, das entweder Nothing (C# null) oder -1 geliefert wird. Stattdessen erhält man den Laufzeitfehler

 

 System.ArgumentNullException: Der Wert darf nicht NULL sein. Parametername: String 
  bei System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) 
  bei System.Number.ParseInt64(String value, NumberStyles options, NumberFormatInfo numfmt) 
  bei Microsoft.AnalysisServices.TraceEventArgs.get_IntegerData() 

 

egal was man macht; eine einfach Prüfung auf IsNothing reicht bereits als Auslöser. Nun könnte man aufwendig auf alle EventClass / EventSubClass Kombinationen filtern, wo zugesichert ein Wert vorkommt. Ich mache es mir einfacher und deswegen kapsele ich die Abfrage des IntegerData, das bei manchen Events den Fortschritt bzw. die Anzahl verarbeiteter Datensätze enthält, in einer eigenen Funktion und fange den Fehler mit Try Catch ab. Betroffen sind von dem Phänomen die Properties CpuTime, Duration, IntegerData, ProgressTotal, Serverty.

 

Der Rest ist einfach, ich lasse die TraceEventArg-Daten in einer Console ausgeben, der VB.Net Code dazu sieht so aus:

 

 

Imports Microsoft.AnalysisServices
 
Module DimProcess
 
    Private WithEvents mSessionTrace As SessionTrace
 
    Sub Main()
        Dim server As New Server
        server.Connect("MeinServer\MeineInstanz")
 
        Dim database As Database = server.Databases("Adventure Works Cube")
        Dim dimension As Dimension = database.Dimensions("Dim Customer")
 
        mSessionTrace = server.SessionTrace
        mSessionTrace.Start()
 
        Console.WriteLine ("{0} Start of processing"Date.Now().ToString("T"))
        dimension.Process(ProcessType.ProcessFull)
 
        mSessionTrace.Stop
        mSessionTrace = Nothing
        Console.WriteLine ("{0} End of processing"Date.Now().ToString("T"))
        
        dimension.Dispose
        database.Dispose
        server.Disconnect
        server.Dispose
 
        Console.WriteLine ("Hit any key")
        Console.ReadKey
    End Sub
 
    Private Sub mSessionTrace_OnEvent(ByVal sender As ObjectByVal e As Microsoft.AnalysisServices.TraceEventArgs) _
        Handles mSessionTrace.OnEvent
        
        Select Case e.EventSubclass            
            ' Uninteressante EventSubClass:
            Case  TraceEventSubclass.Subscribe, TraceEventSubclass.SqlQuery, _
                  TraceEventSubclass.DiscoverXmlMetadata, TraceEventSubclass.ExecuteSql
            Case Else
                If Not String.IsNullOrEmpty(e.TextData) AndAlso not e.TextData.StartsWith("<"then
                    Console.WriteLine ("{0} {1} {2}"Date.Now().ToString("T"), GetIntegerdata(e), e.TextData)
                end if
        End Select
        
    End Sub
 
    Private Function GetIntegerdata(ByVal e As TraceEventArgsAs string
 
        Try
            Dim result As long = e.IntegerData
            Return result.ToString().PadLeft(6)
 
        Catch ex As Exception
            Return String.Empty.PadLeft(6)
        End Try
 
    End Function
 
End Module

 

Zugegeben, mit dem AdventureWork Demo gibt es nicht groß Daten zu verarbeiten, deswegen ist die Ausgabe auch nicht gerade spektakulär:

 

ProcessCubeObject.jpg

Weiterlesen

Übersicht über alle Berichte ... als SSRS Bericht

17. Februar 2011 , Geschrieben von Olaf Helper Veröffentlicht in #Reporting

Auf Websites sieht man häufiger Übersichtsseiten (Index) mit Links zu allen vorhandenen Seiten. Das ist sehr praktisch, man kann auf der Seite selbst nach Begriffen suchen und schnell auf Seiten navigieren, ohne sich lange durch diverse Menüs hangeln zu müssen.

 

Für eine umfangreiche Report Sammlung im Microsoft SQL Server Reporting Services wäre so was auch nicht verkehrt, also gehen wir das mal an.

 

Alle hierfür benötigten Daten sind in der ReportServer Datenbank in der Tabelle dbo.Catalog vorhanden.
Das Feld „
Type“ kennzeichnet die Objektart, hierbei sind 1 = Folder und 2 = Report für die Übersicht von Interesse, 4 = verlinkte Reports lassen wir mal aus. Über die „ItemId“ und „ParentId“ wird die hierarchische Struktur abgebildet. Hier bietet sich einem zur Abfrage natürlich eine rekursive CTE (Common Table Expression) an. Es wird zunächst das Root Element selektiert (ParentID IS NULL) und dann alle Children über einen JOIN mittels ItemId = ParentID auf CTE selbst.

 In der Übersicht soll dann auch eine Jump-to Action möglich sein, um zum Report springen zu können. Dafür kann man die Daten aus dem Feld „Path“ verwendet werden, es enthält die relative Pfadangabe des Elementes. Bei der Selektion wird der „Path“ bereits so modifiziert, um die Daten für einen HyperLink im Report verwenden zu können. Es muss dabei nur ein paar Kleinigkeiten beachtet werden, so müssen (gemäß Url Regel) die Slash’s durch %2f und Leerzeichen durch ein Pluszeichen ersetzt werden. Zudem müssen Berichte über „/Reports.aspx“ und Ordner entsprechend über „/Folder.aspx“ aufgerufen werden.  
 Schlussendlich, um es halbwegs gemäß der Hierarchie sortieren zu können, muss der Pfad des übergeordneten Elementes als primäre Sortierung verwendet werden; dank CTE kann das aber problemlos mitselektiert werden. 
   
 So sieht nun die Selektion der benötigten Daten als CTE aus: 
   
 -- Selektion aller vorhandenen Folder und Reports 
 -- über eine rekursive CTE  
   
 DECLARE @url varchar(100); 
 -- Url vom ReportManager; muss entsprechend angepasst werden 
 SET @url = 'http://MyServer/Reports_MyInstanz/Pages/§§§ReportOrFolder§§§.aspx?ItemPath='; 
   
 ;WITH RPT AS 
 ( -- Root Pfad 
  SELECT RT.ItemID 
  ,RT.Path 
  ,RT.ModifiedDate 
  ,0 AS [Level] 
  ,CAST(N'Stamm' AS nvarchar(425)) AS ReportName 
  ,CAST(N'Stamm' AS nvarchar(425)) AS ParentFolder 
  ,RT.Path AS ParentPath 
  ,REPLACE(REPLACE(RT.Path, '/', '%2f'),' ', '+') AS ReportLink 
   ,RT.Type AS ObjType 
  FROM dbo.Catalog AS RT 
  WHERE RT.ParentID IS NULL 
  AND RT.Type = 1 -- Nur den Root Folder 
  UNION ALL 
  SELECT CHILD.ItemID 
  ,CHILD.Path 
  ,CHILD.ModifiedDate 
  ,RPT.[Level] + 1 AS [Level] 
  ,CHILD.Name AS ReportName 
  ,CASE WHEN CHILD.Type = 1 THEN CHILD.Name ELSE RPT.ReportName END AS ParentFolder 
  ,CASE WHEN CHILD.Type = 1 THEN CHILD.Path ELSE RPT.ParentPath END AS ParentPath 
  ,REPLACE(REPLACE(CHILD.Path, '/', '%2f'),' ', '+') AS ReportLink 
   ,CHILD.Type AS ObjType  
  FROM dbo.Catalog AS CHILD 
  INNER JOIN  
  RPT ON CHILD.ParentID = RPT.ItemID 
  WHERE CHILD.Type = 2 -- Alle Reports und nur nicht-leere Folders 
  OR (CHILD.Type = 1 
  AND EXISTS (SELECT 1 FROM dbo.Catalog AS SUB 
  WHERE SUB.Type IN (1, 2) 
  AND SUB.ParentID = CHILD.ItemID)) 
 ) 
 SELECT RPT.Path 
  ,RPT.ReportName 
  ,CASE WHEN RPT.ObjType = 1 THEN REPLACE(@url, '§§§ReportOrFolder§§§', 'Folder') 
  ELSE REPLACE(@url, '§§§ReportOrFolder§§§', 'Report') 
  END 
  + RPT.ReportLink 
  + CASE WHEN RPT.ObjType = 1 THEN '&ViewMode=List' ELSE '' END 
  AS Link 
  ,RPT.ObjType 
  ,RPT.ModifiedDate 
  ,RPT.Level 
  ,RPT.ParentFolder 
  ,RPT.ParentPath 
 FROM RPT 
 ORDER BY RPT.ParentPath 
  ,RPT.Path 
  ,RPT.ReportName; 

 

 

Der Report für die Übersicht habe ich zunächst recht einfach als eine Tabelle mit 2 Zeilen, eine für Ordner und eine für Berichte, gestaltet. Die Zeilen werden dann je nach „ObjType“ sichtbar geschaltet.

Eine optische „Hierarchie-Tiefe“ der Elemente wird über die Padding - Left Eigenschaft der Textbox erreicht; hier wird über einen Ausdruck der Wert des CTE Feldes „Levels“ gesetzt und so das Feld nach rechts verrückt.

Als „Action“ wird dann „Gehe zu Url“ verwendet, das an die Daten der Selektion-Feldes „Link“ gebunden wird.

 

ReportLinkAction.jpg

 

Und das Ergebnis sieht dann so wie unten aus. Zugegeben, man kann das optisch noch attraktiver gestalten, da kann jeder seiner Kreativität freien Lauf lassen. Wenn die Reportnamen nicht zu lang und die Strukturebene nicht zu tief ist, könnte man den Bericht auch in 2 Spalten gliedern, um Platz zu sparen.

 

ReportOverview 

 

Der Report kann als „ReportOverview.rdl“ Datei fürs BIDS 2008 bzw. Report Builder 2.0 von meinem SkyDrive herunter geladen werden:

Weiterlesen

SQL Account "sa" als Nicht-SysAdmin

15. Februar 2011 , Geschrieben von Olaf Helper Veröffentlicht in #MSSQL

Man hört und sieht es immer noch häufiger:

Auch heutzutage, wo jedem das Thema Sicherheit präsent sein sollte, gibt es weiterhin viele, kleine oder größere Applikationen, die auf einen MS SQL Server zugreifen und das mit dem SQL Account "sa", welcher nicht zu selten über kein strenges oder noch schlimmer, über gar kein Passwort verfügt; mal abgesehen davon, dass es eh jeder kennt. Dabei ist dieser Standard SysAdmin Account eigentlich sowieso auch nur für die Administration gedacht gewesen; wie es halt immer so ist.

 

Natürlich sollte sowas von Grund auf geändert werden, also das die Anmeldung über den Windows Account des aktuellen Benutzers erfolgt oder zumindest über einen für die jeweilige Applikation dediziert angelegten SQL Account, der über ein strenges Passwort verfügt.

 

Durch die Masse an Applikationen ist eine solche Änderung natürlich zeitaufwendig; und was ist in der Zwischenzeit, bis alle Zugriffe geändert sind? Weiterhin dieses Sicherheitsrisiko eingehen mit der Gefahr, dass jemand "ungewünschte Änderungen" vornimmt und Daten oder gar ganze Objekte löscht?

 

Dafür gäbe es eine Möglichkeit zur Lösung. Seit dem Microsoft SQL Server Version 2005 gibt es die Möglichkeit SQL Account‘s mittels eines einfach ALTER LOGIN umzubenennen, einschließlich dem "sa" Account.

Die Idee ist also folgende:

-       "sa" umbenennen, z.B. in "saRealAdmin"

-       Strenges Passwort für "saRealAdmin" vergeben

-       Neuen SQL Account "sa" mit dem ursprünglichen Passwort anlegen und ihm die minimalst benötigten Rechte geben.

 

Versuchen wir es mal (Empfehlung: Vorher die [master] Datenbank kopieren!):

 

 USE [master] 
 GO 
   
 -- Original "sa" umbenennen 
 ALTER LOGIN [sa] WITH NAME = [saRealAdmin] 
 GO 
 -- Neuen "sa" mit altem Pwd anlegen 
 CREATE LOGIN [sa] WITH PASSWORD=N'altesPasswort' 
 GO 
   
 -- Kontrolle; beide da 
 SELECT sid, name 
 FROM [master].[sys].[syslogins] 
 WHERE name LIKE 'sa%' 
 GO 
   
 -- In AdventureWorks als DB User anlegen 
 -- und nur Lese-Rechte vergeben 
 USE [AdventureWorks] 
 GO 
 CREATE USER [sa] FOR LOGIN [sa] 
 GO 
 EXEC sp_addrolemember N'db_datawriter', N'sa' 
 GO 
   
 -- Test neuer "sa" auf Rechte 
 EXECUTE AS LOGIN = 'sa'; 
 GO 
 DROP TABLE Person.Address 
 GO 
   
 -- User Context wieder zurück schalten 
 REVERT; 

 

Der Test hat geklappt, die Anmeldung mit dem neuen „sa“ funktioniert, die Rechte sind eingeschränkt und auch die Verwendung des vermeintlich alten „saRealAdmin“ funktioniert einwandfrei und hat natürlich weiterhin Admin-Rechte.

 

Auf die Art kann man die Zwischenzeit überbrücken und trotzdem arbeiten Applikationen, die „sa“ verwenden weiterhin.

Nach Umstellung aller Apps sollte man sich überlegen, die Umbenennung rückgängig zu machen, sonst denkt der Admin womöglich nicht mehr daran, einen andern Sql Account zu verwenden.

Weiterlesen

Microsoft SQL Server FileStream

5. Mai 2010 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

SQL FileStream zum effektiven Speichern von BLOBs = Binary Large Objects ist im Microsoft SQL Server ab Version 2008 neu hinzugekommen. Es kombinierte die Vorteile der Ablage im SQL Server als VarBinary Daten mit der Möglichkeit der transaktionellen Verarbeitung und der Ablage im File-System mit der performanten Zugriffsmöglichkeit über Windows Streaming / API Zugriff.

 

Es gibt ein wirklich sehr gutes und umfangreiches Whitepaper „FILESTREAM Storage in SQL Server 2008“ im MSDN Bereich von Paul S. Randall, das alle Aspekte rund um FileStream beleuchtet. Was soll ich dem hinzufügen?

 

Ich habe nun auch mal etwas experimentiert und ein paar erste Erfahrungen gesammelt:

·         Mein erster Test war unter Windows XP mit MS SQL Server 2008 Express Edition ohne SP, der unter dem Account „NetworkServices“ lief. Die Anlage der Dateigruppe für FileStream schlug mit einer nicht gerade aussagekräftigen Fehlermeldung fehl wie
Unable to open the physical file "c:\Program Files\Microsoft SQL Server\...". Operating system error -2147024891: "0x80070005(Access is denied.)"
 Eine kurze Recherche ergab, dass der Dienst unter einem Windows Account laufen muss, damit es funktioniert. Einen entsprechenden Eintrag gibt es bereits bei MS Connect. Mit meiner Developer Edition unter Windows Vista mit Dienstkonto „Local System“ hingegen funktionierte es ohne Änderungen.

·         Änderungen an FileStream Daten, also UPDATE und DELETE, werden nicht direkt im Transaktionsprotokoll protokolliert, sondern in Form von revisionierten Dateien. Diese verbleiben im Dateisystem bis zur nächsten Voll- bzw. Log-Sicherung; das muss man bei der Planung des Speicherplatzes beachten.

 

 USE [master] 
 GO 
 EXEC sp_configure filestream_access_level, 2; 
 GO 
 RECONFIGURE; 
 GO 
   
 ALTER database AdventureWorks 
 ADD FILEGROUP [FileStreamFG] 
 CONTAINS FILESTREAM 
 GO 
   
 ALTER database AdventureWorks 
 ADD FILE 
 ( 
  NAME= 'FileStream', 
  FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10.SQL10DEV\FG' 
 ) 
 TO FILEGROUP [FileStreamFG] 
 GO 
   
 USE [AdventureWorks] 
 GO 
   
 CREATE TABLE dbo.FileStreamStorage 
  ( 
  [Id] int NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
  [Guid] uniqueidentifier NOT NULL UNIQUE ROWGUIDCOL DEFAULT NEWID(), 
  [FileName] varchar(255) NOT NULL, 
  [FileStreamData] varbinary(MAX) FILESTREAM NULL  
  ) ON [PRIMARY] 
  FILESTREAM_ON [FileStreamFG] 
 GO 
   
 INSERT INTO dbo.FileStreamStorage ([FileName], [FileStreamData]) 
 VALUES ('Test1.txt', CONVERT(varbinary(max), N'Hello World')); 
   
 INSERT INTO dbo.FileStreamStorage ([FileName], [FileStreamData]) 
 VALUES ('Test2.txt', CONVERT(varbinary(max), N'Hello World again')); 
   
 INSERT INTO dbo.FileStreamStorage ([FileName], [FileStreamData]) 
 VALUES ('Test3.txt', CONVERT(varbinary(max), N'Hello World again')); 
   
 INSERT INTO dbo.FileStreamStorage ([FileName], [FileStreamData]) 
 VALUES ('Test4.txt', CONVERT(varbinary(max), 'Hello World again')); 
 GO 
   
 DELETE FROM dbo.FileStreamStorage 
 WHERE [Id] <= 4; 
Weiterlesen

Referenzdaten Bankleitzahlen

30. April 2010 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Gute, weil vollständige und korrekte Referenzdaten, sind schwierig zu finden; in der Regel kann man sie nur bei kommerziellen Anbieter für einiges an Geld beziehen.

Referenzdaten, die dann auch noch regelmäßig aktualisiert werden und zu allem Überfluss auch noch frei verfügbar sind, sind eine Seltenheit.

Das Verzeichnis für deutsche Bankleitzahlen ist so eine Seltenheit. Sie wird von der Deutschen Bundesbank herausgegeben, ist auf deren Seite frei verfügbar und wird auch quartalsweise aktualisiert. Eine Dokumentation des Dateiformates gibt es auch.

Das Dateiformat ist einfach gehalten, es eine Textdatei und die Spalten haben jeweils eine fester Breite. In dem Fall ist die einfachste Möglichkeit, die Daten zu importieren, mit OpenRowSet und der Bulk Option zu arbeiten. Als ich mir die Dokumentation dazu durchgelesen habe, fiel mir auf, dass zwar ausführlich die Anwendung für zeichengetrennte Formate beschrieben ist inklusive Beispiele, aber in keiner Weise, wie man Daten mit fester Spaltenbreite handhabt. Also Mut zur Lücke, eine Formatdatei definiert ohne Trennzeichen und die Spaltenbreite angegeben; die maximal Breite muss man eh festlegen und siehe da, der Import per BULK funktioniert einwandfrei.

Kleines Problem ist, das der Dateiname „versioniert“ wird, also der Dateiname das Datum der Veröffentlichung beinhaltet. Zwar gibt es fest definierte Regeln, wann das neue Verzeichnis veröffentlicht wird, man kann das Datum errechnen, aber das erschwert den Automatismus, um die Datei per SSIS über FTP / http herunter zu laden, um sie dann weitere zu verarbeiten.

 

Hier nun der Aufbau der Format-Datei und das Statement für den Bulk – Import; die gesamte SSMS Solution gibt es auch zum Download, sie beinhaltet auch das Tabellen Design.

 

Format Datei BLZ_Format.txt:

 

 8.0 
 13 
 1 SQLCHAR 0 8 "" 1 Blz "" 
 2 SQLCHAR 0 1 "" 2 BlzFuehrend "" 
 3 SQLCHAR 0 58 "" 3 Bezeichnung "" 
 4 SQLCHAR 0 5 "" 4 Plz "" 
 5 SQLCHAR 0 35 "" 5 Ort "" 
 6 SQLCHAR 0 27 "" 6 Kurzbezeichnung "" 
 7 SQLCHAR 0 5 "" 7 InstitutsnummerPAN "" 
 8 SQLCHAR 0 11 "" 8 Bic "" 
 9 SQLCHAR 0 2 "" 9 PruefzifferMethode "" 
 10 SQLCHAR 0 6 "" 10 Nummer "" 
 11 SQLCHAR 0 1 "" 11 Aenderung "" 
 12 SQLCHAR 0 1 "" 12 Loeschung "" 
 13 SQLCHAR 0 8 "\n" 13 NachfolgerBlz "" 

 

Das SQL Statement für den Import über OpenRowSet.

 

 -- Daten einfügen 
 INSERT INTO [BLZ].[dbo].[Blz] 
  ([Blz] 
  ,[BlzFuehrend] 
  ,[Bezeichnung] 
  ,[Plz] 
  ,[Ort] 
  ,[Kurzbezeichnung] 
  ,[InstitutsnummerPAN] 
  ,[Bic] 
  ,[PruefzifferMethode] 
  ,[Nummer] 
  ,[Aenderung] 
   ,[Loeschung] 
  ,[NachfolgerBlz])  
 SELECT [Blz] 
  ,CONVERT(tinyint, [BlzFuehrend]) AS BlzFuehrend 
  ,RTRIM([Bezeichnung]) AS [Bezeichnung] 
  ,[Plz] 
  ,RTRIM([Ort]) AS [Ort] 
  ,RTRIM([Kurzbezeichnung]) AS [Kurzbezeichnung] 
  ,CONVERT(int, CASE WHEN [InstitutsnummerPAN] = '' 
  THEN NULL 
  ELSE [InstitutsnummerPAN] 
  END) AS [InstitutsnummerPAN] 
  ,CASE WHEN [Bic] = ''  
   THEN NULL 
  ELSE [Bic] END AS [Bic] 
  ,[PruefzifferMethode] 
  ,CONVERT(int, [Nummer]) AS [Nummer] 
  ,[Aenderung] 
  ,CONVERT(bit, [Loeschung]) AS [Loeschung] 
  ,[NachfolgerBlz] 
 FROM OPENROWSET(BULK N'D:\Projekte\Blz\blz_20100308.txt' 
  ,FORMATFILE = N'D:\Projekte\Blz\blz_format.txt' 
  ,CODEPAGE = 'OEM'  
  ,ERRORFILE = N'D:\Projekte\Blz\blz_error.txt' 
  ) AS Blz 
 GO 
Weiterlesen

Microsoft Visual Studio 2010 Express Edition - DEU

29. April 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Ich hätte ja noch etwas warten können ... nun gibt es die Microsoft Visual Studio 2010 Express Editions auch als deutsche Version im Download.

Weiterlesen
<< < 1 2 3 4 5 6 7 8 9 10 20 > >>