SQL Server & ASP .NET Blog

Interessantes und Wissenswertes

Reporting Services – Reports auf einen anderen Server übertragen

Ich habe hier zig Reports und möchte diese auf einen anderen Server umziehen. Dazu muss ich aber nicht jedes Report-Projekt öffnen und neu bereitstellen. Nein! Der Reporting Services Scripter http://www.sqldbatips.com/showarticle.asp?ID=62 kann mir diese Arbeit zum Glück abnehmen. Einfach den Quellserver, den Zielserver und die jeweiligen Pfade zur RS.exe konfigurieren – zu übertragende Reports auswählen und schon ist der neue Server gefüllt.

image

Visual Studio (C#) – Fehlende Using-Direktiven (halb)automatisch einfügen

Ein kleiner Tipp. Teilweise tippt man munter drauf los, ohne vorher die benötigten “using” Direktiven anzugeben. Visual Studio merkt das und unterstreicht die verwendete Klasse rot.

sqlcon

Nun kann man – entweder die using-Direktive manuell eingeben, oder – man drückt [STRG] + [.] und ein Kontextmenü klappt auf und die Direktive kann direkt automatisch eingebunden werden.

sqlcon2

Funktioniert mit Visual Studio 2008 und 2010 (ob es in 2005 schon ging, habe ich nicht getestet).

ASP .NET - Bild aus Datenbank abrufen und anzeigen

In einem anderem Beitrag [hier]habe ich bereits beschrieben, wie einfach es ist, ein Bild auf einer Webseite hochzuladen und mit wenigen Zeilen C#-Code in einer SQL Server Datenbank zu speichern. Interessant ist natürlich auch der Rückweg: Also wie kommt das Bild wieder aus der Datenbank heraus und kann im Browser angezeigt werden?

Auch das geht wieder in einfachen Schritten.

Schritt 1 – Eine ASPX-Seite zur Ausgabe eines Bildes

Um ein Bild aus der Datenbank zu lesen und im Browser anzuzeigen, erstelle ich eine neue Seite “GetPicture.aspx”. Diese Seite hat keinen eigentlichen Inhalt, sondern nur den Zweck ein Bild anhand des Namens (oder eines beliebigen anderen Parameters, z. B. einer ID) aus der Datenbank zu holen und an den Browser zu senden.

protected void Page_Load(object sender, EventArgs e)
{
//Variable für die Bilddaten
Byte[] myFile;
//der Dateiname aus dem QueryString
string myFileName = Request.QueryString["FileName"];
if (myFileName != null)
{
//Verbindung zum Server
SqlConnection con = 
new SqlConnection("Data Source=192.168.1.13;Initial Catalog=BildDB;User ID=xxx;Password=xxx");
//Insert Statement mit den entsprechenden Parametern
SqlCommand cmd = new SqlCommand("SELECT picture FROM pictures WHERE name = @name", con);
//Parameter für den Bildnamen
SqlParameter paramName = new SqlParameter("@name", System.Data.SqlDbType.VarChar);
paramName.Value = myFileName;
cmd.Parameters.Add(paramName);
//Daten lesen
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read() ) //im Beispiel interessiert nur der erste Satz
{
myFile = (Byte[])reader["picture"];
Response.ContentType = "image/jpeg"; //ContentType setzen
Response.BinaryWrite(myFile);        //Bild ausgeben
}
con.Close();
}      

Ruft man nun diese Seite mit einem in der Datenbank vorhandenen Bildnamen auf, dann wird das Bild direkt im Browser angezeigt.

image

Schritt 2 – Bilder in einem Gridview anzeigen

Um nun mehrere Bilder aus der Datenbank anzuzeigen kann bspw. ein GridView verwendet werden. Auf einer zusätzlichen Seite “Anzeigen.aspx” habe ich eine neue SQLDatasource und ein GridView erstellt.

        <!-- Die Datenquelle -->
<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
ConnectionString="<%$ ConnectionStrings:BildDBConnectionString %>" 
SelectCommand="SELECT picture, name, addedat FROM [pictures]">
</asp:SqlDataSource>
<!-- Anzeige im Gridview -->
<asp:GridView ID="GridView1" runat="server" 
DataSourceID="SqlDataSource1" 
AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
<asp:BoundField DataField="addedat" HeaderText="addedat" 
SortExpression="addedat" />
<asp:ImageField DataImageUrlField="name" 
DataImageUrlFormatString="~/GetPicture.aspx?Filename={0}">
</asp:ImageField>
</Columns>
</asp:GridView>

Das “Besondere” an diesem GridView ist nun, dass es ein ImageField hat, welches direkt die in Schritt 1 erstellte ASPX-Seite aufruft und den aus der Datenbank gelieferten Dateinamen übergibt.

Das Endergebnis sieht dann so aus:

image 

Das Projekt (Visual Studio 2010) hängt zum Anschauen direkt hier am Beitrag. Fragen sind natürlich immer gern gesehen ;)

Bildverwaltung.zip (32,13 kb)

Server Trigger – DROP DATABASE verhindern

Nur ein kurzer Tipp: Möchte man verhindern, dass Datenbanken auf einem Server gelöscht werden, kann man dies durch einen Trigger auf dem Server tun.

CREATE TRIGGER TR_LoeschenVerhindern 
ON ALL SERVER 
FOR DROP_DATABASE 
AS 
PRINT 'Um eine Datenbank zu löschen muss erst der Trigger TR_LoeschenVerhindern deaktiviert werden.'
ROLLBACK;

Wird nun versucht die Datenbank zu löschen, gibt es folgende Meldung:

Um eine Datenbank zu löschen muss erst der Trigger TR_LoeschenVerhindern deaktiviert werden.
Msg 3609, Level 16, State 2, Line 1
The transaction ended in the trigger. The batch has been aborted…
…so kann niemand mehr sagen, die Datenbank ist "ausversehen” abhanden gekommen ;-)

Fehler beim Erstellen des Steuerelements ...

Beim Öffnen einer Website in Visual Studio kann es vorkommen, dass einige Steuerelemente nicht korrekt angezeigt werden können.

Die Fehlermeldung (als Beispiel): "Fehler beim Erstellen des Steuerelements: <Elementname> asp:UpdatePanel konnte nicht für die ContentTemplate-Eigenschaft festgelegt werden." erscheint.

Woher diese Fehlermeldung kommt, weiß ich leider (noch) nicht. Auf jeden Fall kann Sie behoben werden: Einfach das Projekt schließen und alle Dateien in "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files" löschen und danach das Projekt wieder öffnen.

Eine weitere Möglichkeit soll sein diese Verzeichnis zu leeren: C:\Dokumente und Einstellungen\<USERNAME>\Lokale Einstellungen\Anwendungsdaten\Microsoft\VisualStudio\9.0\ProjectAssemblies (hat bei mir nicht funktioniert)

OUTPUT – Gelöschte oder eingefügte Sätze ausgeben

Um zu prüfen, bzw. anzuzeigen welche Sätze nach einem DELETE gelöscht wurden, kann die OUTPUT Klausel verwendet werden. Hier ein kleines Beispiel.

Wir haben eine Tabelle mit einer Identitätsspalte und einem Wert und fügen dort ein paar Werte ein:

CREATE TABLE toDelete
(
id int primary key identity(1,1),
value int
)
insert into todelete values (1)  
insert into todelete values (2)
insert into todelete values (3)
insert into todelete values (4)

Will ich nun alle Datensätze löschen, deren Wert > 2 ist und diese auch noch ausgeben (um diese beispielsweise einem Benutzer anzuzeigen), dann verwende ich die OUTPUT-Klausel:

delete toDelete
OUTPUT DELETED.value
WHERE value > 2

Ergebnis ist folgendes:

output

Das gleiche funktioniert auch mit der Tabelle INSERTED, wenn zum Beispiel neue Werte der Identitätsspalte angezeigt werden sollen.

INSERT INTO toDelete 
OUTPUT INSERTED.*
VALUES (5)

Ergebnis hier ist:

image

Damit kann man sich ein weiteres SELECT auf die Tabelle sparen.

UNIQUE - Mehrere NULL

Um sicherzustellen, dass eine Spalte einer Tabelle nur eindeutige Werte enthält, kann diese Spalte um einen UNIQUE constraint ergänzt werden. Zum Beispiel:

CREATE TABLE uniq
(
id int primary key identity(1,1),
val int unique
)

Bei dieser Tabelle verhindert der SQL-Server, dass gleiche Werte in die Spalte “val” eingefügt werden. Versucht man also folgendes:

INSERT INTO uniq VALUES (1)
INSERT INTO uniq VALUES (2)
INSERT INTO uniq VALUES (1)

…erhält man diese Fehlermeldung:

Msg 2627, Level 14, State 1, Line 3
Violation of UNIQUE KEY constraint 'UQ__uniq__21B6055D'. Cannot insert duplicate key in object 'dbo.uniq'.

So weit, so gut. Was passiert nun aber, wenn man mehrere NULL-Werte einfügen möchte?

INSERT INTO uniq VALUES (NULL)
INSERT INTO uniq VALUES (NULL)

…es erscheint die gleiche Fehlermeldung.

(1 row(s) affected)
Msg 2627, Level 14, State 1, Line 2
Violation of UNIQUE KEY constraint 'UQ__uniq__21B6055D'. Cannot insert duplicate key in object 'dbo.uniq'.
The statement has been terminated.

Aber wie kann das sein? NULL ist doch ein unbestimmter Wert (eigentlich nichtmal ein Wert), nicht vergleichbar und kann somit verglichen mit sich selbst nie gleich sein ;-) Nunja, ist er im SQL Server aber doch. Ist es also notwendig eine Spalte eindeutig zu haben geht das im SQL Server nicht…oder doch? Mehr...

SQL - Leerzeichen in der Mitte eines String entfernen...INNERTRIM()?

Habe mich gerade gefragt, wie ich die Leerzeichen innerhalb eines VARCHAR entfernen kann. Also aus "Blah Blah" wird "BlahBlah". Schon hundert-tausend-mal gemacht, trotzdem habe ich plötzlich nach einer Art "INNERTRIM" gesucht :-D.

Natürlich geht das ganz einfach mit REPLACE(feld, ' ', '')

Falls jemand über die Suche nach INNERTRIM hierher gelangt ist, dann hätte ich gern einen Kommentar :-)

Cube aus relationalem SQL abfragen

Um einen Cube per MDX-Statement aus dem relationalen SQL abfragen zu können um ggf. mit den Ergebnissen weiter zu arbeiten kann folgendes Konstrukt verwendet werden:

SELECT *
FROM
OPENROWSET('MSOLAP','Data Source=YOUR_SERVER;Initial Catalog=YOUR_CATALOG;','<YOUR MDX Statement>')

Dieses Statement liest das Ergebnis der MDX-Abfrage und gibt es aus. Natürlich kann man dann mit dem Ergebnis weiterarbeiten und es bspw. in eine temporäre Tabelle schreiben etc.

Wichtig dabei ist, dass OPENROWSET aktiviert ist. Diese Einstellung kann per SQL Server Surface Area Configuration (SQL Server 2005) unter Surface Area Configuration for Features => Ad Hoc Remote Queries aktiviert werden.

SSIS – Startobjekt in einem Projekt

Nur ein kleiner Tipp. Beim Debugging von SSIS-Paketen kann innerhalb eines Projektes ein Paket als Startobjekt gewählt werden (durch Rechtsklick und “Set as StartUp Object”). Will man nun ein einzelnes Paket debuggen startet immer dieses Paket. Soll das wieder geändert werden genügt ein Klick in die Projekteigenschaften im Bereich “Debugging”.

startprojekt

Dort kann das Startup Object wieder abgewählt werden, so dass das jeweils aktive Paket gestartet wird.