none
Anzahl selectierter Datensätze als output RRS feed

  • Frage

  • Hallo zusammen,


    ich möchte in asp.net ein Dataset mit pager erstellen und benötige hierzu die Gesamtanzahl der selectierten Datensätze. Diese fallen je nach Bedingungen unterschiedlich aus.

    Ich habe diese Prozedur mal als Vorlagen genommen.

    ALTER PROCEDURE [dbo].[spx_PagerS]
        @PageNo int = 1,
        @ItemsPerPage int = 20,
        @TotalRows int out
    AS
    BEGIN
      SET NOCOUNT ON
      DECLARE
        @StartIdx int,
        @SQL nvarchar(max), 
        @SQL_Conditions nvarchar(max), 
        @EndIdx int
       
        IF @PageNo < 1 SET @PageNo = 1
        IF @ItemsPerPage < 1 SET @ItemsPerPage = 10

        SET @StartIdx = (@PageNo -1) * @ItemsPerPage + 1
        SET @EndIdx = (@StartIdx + @ItemsPerPage) - 1
        SET @SQL = 'with rsc as(SELECT kursid, themen
                    FROM (
                    SELECT  ROW_NUMBER() OVER(ORDER BY kursid) AS Row, *
                          FROM  seminar where dokstatus <=2 ) AS tbl WHERE  Row >= '
                            + CONVERT(varchar(9), @StartIdx) + ' AND
                           Row <=  ' + CONVERT(varchar(9), @EndIdx)+')'
       set @sql = @sql + 'select * from rsc'                   
        EXEC sp_executesql @SQL

        SET @SQL = 'SELECT @TotalRows=COUNT(*) FROM rsc'
        EXEC sp_executesql
            @query = @SQL,
            @params = N'@TotalRows INT OUTPUT',
            @TotalRows = @TotalRows OUTPUT
    END

    Nach Ausführen der Prozedur wird mit ein Fehler in folgender Zeile ausgeworfen,

    SET @SQL = 'SELECT @TotalRows=COUNT(*) FROM rsc'

    Das Object 'rsc' ist nicht bekannt. Das ist mir auch verständlich.

    Wie kann ich die Prozedur umschreiben, damit @totalrows mir die Anzahl der Datensätze auswirft, die tatsächlich selectiert worden sind ?

    Ich würde mich über eine Antwort sehr freuen, ich such schon seit Tagen nach einer Lösung.



    Liebe Grüße, die Luzie!
    Montag, 7. Juni 2010 15:55

Antworten

  • Hallo Luzie,

    wenn Du für das Hauptergebnis einen SqlDataAdapter verwendest, ist der Einsatz
    von zwei SqlCommand Instanzen sinnvoller. Um den Ausgabeparameter zu erhalten,
    benötigst Du keinen DataAdapter.  Ein ExecuteNonQuery für das SqlCommmand
    und abrufen des Parameters ("@TotalRows") danach reicht, siehe
    Ändern von Daten mit gespeicherten Prozeduren (ADO.NET)
    (das hier nichts geändert wird ist dafür ohne Belang).

    Was den Fehler bei der Parameterübergabe angeht:
    Und die Meldung bezüglich der falschen Konvertierung resultiert daraus,
    dass versucht wird, den @search-Parameter als @PageNo zu interpretieren.

    Alle bei sp_executesql verwendeten Parameter müssen in @paramlist
    deklariert werden, und dann genau in der Reihenfolge aufgeführt werden.
    Und bei Dir ist @search der Dritte (und nicht der 1.):

    SET @paramList = '@PageNo int, @ItemsPerPage int,@search varchar(255)'                      

    Umgekehrt spielt es keine Rolle, ob der Parameter effektiv verwendet wird,
    so dass Du auch mal einige "auf Vorrat" übergeben kannst.

    Gruß Elmar

    • Als Antwort markiert Luzie Samstag, 12. Juni 2010 07:42
    Donnerstag, 10. Juni 2010 18:32

Alle Antworten

  • Hallo Luzie,

    Deine RSC CTE ist nur beim ersten sp_executesql verfügbar,
    die zweite Anweisung weiß davon nichts mehr.
    Dort müsstest Du den SQL Text ebenfalls einfügen.

    Wovon ich aber abraten würde.
    Denn nicht nur dass die Abfrage zweimal ausgeführt werden muß,
    was nicht gerade geschwindigkeitsteigernd ist.
    Ausgabevariablen stehen erst nach dem Abarbeiten aller Ergebnismengen
    (hier der ersten Abfrage) zur Verfügung.
    Wenn Du aber wiederum die Daten der ersten Abfrage verarbeitet hast,
    kannst Du ohnehin feststellen, wieviele Zeilen Du gerade verarbeitet hast.
    Womit die zweite Abfrage (und Ausgabevariable) flüssiger als flüssig ist.

    Deswegen ist es wesentlich sinnvoller einmal direkt abzufragen.
    Zumal Du auch ganz ohne dynamisches SQL klarkommst:

    ALTER PROCEDURE [dbo].[spx_PagerS]
      @PageNo int = 1,
      @ItemsPerPage int = 20,
      @TotalRows int out
    AS
    BEGIN
     SET NOCOUNT ON
     DECLARE
      @StartIdx int,
      @EndIdx int
      
      IF @PageNo < 1 SET @PageNo = 1
      IF @ItemsPerPage < 1 SET @ItemsPerPage = 10
    
      SET @StartIdx = (@PageNo -1) * @ItemsPerPage + 1
      SET @EndIdx = (@StartIdx + @ItemsPerPage) - 1;
    
      WITH rsc 
      AS
      (
        SELECT tbl.kursid, tbl.themen
        FROM (SELECT 
          ROW_NUMBER() OVER(ORDER BY kursid) AS Row, 
          kursid, 
          themen
          FROM seminar 
          WHERE dokstatus <= 2) AS tbl 
        WHERE tbl.Row >= @StartIdx AND tbl.Row <= @EndIdx
      )
      SELECT * FROM rsc;
      -- Immer noch überflüssig
      SET @TotalRows=@@ROWCOUNT;
    END
    Das liest sich IMO gleich viel freundlicher (wenn auch ungetestet).
    @TotalRows habe ich mehr der Vollständigkeit halber via @@ROWCOUNT befüllt,
    aber notwendig wäre das nicht wie gesagt nicht.

    Gruß Elmar

    Montag, 7. Juni 2010 17:26
  • Hallo Elmar,

    erstmals vielen herzlichen Dank für die Antwort.

    Mein Beispiel ist nur eine ganz abgespeckte Version der eigentlichen Prozedur. Ich traue mich gar nicht, die komplette Version hier zu posten, ihr schlagt bestimmt die Hände über dem Kopf zusammen, aber trotzdem, ich komme vermutlich um das dyn. SQL vermutlich nicht herum. Und diese muss noch um 2 zusätzliche Abfrgen erweitert werden, je nach Anforderung über den Paramter @sicht. Ich muss diese Sichten zur Laufzeit austauschen, weil die Verknüpfungen im Falle der Aufforderungen doppelte Datensätze (verschiedene Kategorien) ergeben müssen. Naja, das funktioniert auch, die ganze Prozedur funktioniert eigentlich.

    Lediglich die Ausgabe der Anzahl der Datensätze, das bekomme ich nicht hin, und die brauche ich für die Generierung des Pagers.

    SET @TotalRows=@@ROWCOUNT;

    gibt mir ja immer nur die aktuelle Anzahl des Seitenaufrufs zurück und das sind nie mehr als 20 Datensätze, die Anzahl, die eben unter @ItemsPerPage angegeben ist, leider nicht die Gesamtanzahl :)

    Aber für die Berechnung der Seitenaufrufe benötige ich die Gesamt-Anzahl.

    Bpsw. die Abfrage ergibt eine Anzahl von 64 Datensätzen und diese durch @ItemsPerPage geteilt, ergibt max. 4 Durchläufe.  Diese Berechnung brauche ich.

    Hast Du noch eine Idee?


    ALTER PROCEDURE [dbo].[sp_seminarPaging1]                             
              @pageNo int = 1,
              @ItemsPerPage int = 20,
              @NEU bit = NULL,
              @BS bit = NULL,
              @CH bit = NULL,
              @sort varchar(20) = 'beginn',
              @search varchar(255) = '%',
              @debug bit = 1,          
              @totalRows int out
     
    AS                  
                                                        

    DECLARE @paramlist nvarchar(1000)
    DECLARE @haswhere bit,
     @StartIdx int,
        @SQL nvarchar(max),  
        @SQL_Conditions nvarchar(max),  
        @EndIdx int,
        @spalten varchar(300) = '',
        @sicht varchar(300) = 'vSeminar'
        
        IF @PageNo < 1 SET @PageNo = 1
        IF @ItemsPerPage < 1 SET @ItemsPerPage = 10

        SET @StartIdx = (@PageNo -1) * @ItemsPerPage + 1
        SET @EndIdx = (@StartIdx + @ItemsPerPage) - 1



       
    SET @SQL = 'with rsSeminar as
    (
        SELECT kursid, CONVERT(char(10), Beginn, 104)
        AS Datum, themen,NEU,BS,CH,kat,zert,'

     if @sort = 'beginn'
            BEGIN
                set @sql = @sql + 'DATENAME(MM, beginn) + '' '' + CAST(YEAR(beginn) AS VARCHAR(4))'
            END
        ELSE IF @sort = 'kat'
            Begin
                set @sql = @sql + 'kat'
            END
        ELSE IF @sort = 'usort'
            Begin
                set @sql = @sql + 'detail'
            END
        ELSE
            BEGIN
                set @sql = @sql + 'detail'
            END
        set @sql = @sql + ' AS sortvar
                    FROM (
                    SELECT  ROW_NUMBER() OVER(ORDER BY ' + @sort +',beginn ASC) AS Row, *
                          FROM  '+@sicht+'
                          where (themen like ' + quotename('%' + @search + '%','''')+ '
            or beschreibung like ' + quotename('%' + @search + '%','''')+ '
            or kurztext like ' + quotename('%' + @search + '%','''')+ ')                     
                          ) AS tbl WHERE  Row >= '
                            + CONVERT(varchar(9), @StartIdx) + ' AND
                           Row <=  ' + CONVERT(varchar(9), @EndIdx)

     --SET @hasWhere = 0
        --IF @BS <> 0
        --BEGIN
        --   SET @sql = @sql + ' and (BS=1'
        --   SET @hasWhere = 1
        --END
        

        --IF @NEU <> 0
        --BEGIN
        --   IF @hasWhere = 0
        --        BEGIN
        --            SET @sql = @sql + ' and (NEU=1'
        --            SET @hasWhere = 1
        --        end
        --   ELSE
        --        SET @sql = @sql + ' and NEU=1'                       
        --END
        
        
        --IF @CH <> 0
        --BEGIN
        --   IF @hasWhere = 0
        --        BEGIN
        --           SET @sql = @sql + ' and (CH=1'
        --           SET @hasWhere = 1
        --        END                
        --    ELSE
        --      SET @sql = @sql + ' and CH=1'                        
        --END

        --IF @hasWhere = 1
        --Begin
        --    SET @sql = @sql + ')'
        --END    
    set @SQL = @SQL +')'
                                                     
    SET @paramList = '@pageNo int,
                        @ItemsPerPage int'                                       


    IF @debug = 1 PRINT @sql

    SET @sql = @sql + 'select * from rsSeminar'
           
    EXEC sp_executesql
            @sql,
            @paramlist,
            @pageNo,
            @ItemsPerPage

    set @sql = 'select @totalRows=count(*) from vSeminar'
    EXEC sp_executesql
    @query = @sql,
    @params = N'@totalRows int output',
    @totalrows = @totalRows Output
    Dienstag, 8. Juni 2010 11:41
  • Hallo

    also ich habe die Bedingungen ein einem Parameter abgespeichert und rufe diesen bei der Ausgabe der Gesamt-Anzahl mit auf.

    Wenn noch jemand eine bessere Idee hat, ich bin für jede Verbesserung dankbar.

     


    Liebe Grüße, die Luzie!
    Mittwoch, 9. Juni 2010 06:04
  • Hallo Luzie,

    wenn Du die Zahl für das Kriterum brauchst, wäre das sinnvollste zwei Abfragen zu verwenden,
    und die Gesamtzahl für weitere Aufrufe zwischenspeichern - letztendlich kostet das weniger,
    als den SQL Server die Abfrage erneut ausführen zu lassen.

    Man kann es auch durch zwei getrennte Aufrufe lösen, was ich unten zeige -
    um beides in einem Rutsch auszuführen, mußt Du nur das SQL etwas umstellen.

    Wichtig erschien mir aber auch die Parameter-Verkettung zu elemenieren -
    nicht nur um SQL Injection vorzubeugen, sondern auch um das Cachen von
    Abfrageplänen zu fördern. Die Suchparameter (@search) kann man ebenso
    wie die übrigen Kriterien dem sp_executesql mitgeben.

    Vorne dran eine frei Nase zusammengestellte Tabelle...

    USE tempdb;
    GO
    
    CREATE TABLE dbo.seminar (
      kursid int not null,
      beginn datetime not null,
      themen varchar(255) null,
      detail varchar(255) null,
      kurztext varchar(255) null,
      beschreibung varchar(255) null,
      kat varchar(10) null,
      neu varchar(10) null,
      bs varchar(10) null,
      ch varchar(10) null,
      zert varchar(10) null)
    GO
    SET NOCOUNT ON;
    DECLARE @row int;
    SET @row = 1
    WHILE @row <= 1000
    BEGIN
      INSERT INTO dbo.seminar(kursid, beginn, themen) 
      VALUES (@row, 
        DATEADD(dd, @row % 30, GETDATE()), 
        CASE @row % 3
          WHEN 1 THEN 'einer'
          ELSE 'alle' END);
      SET @row += 1;
    END
    GO
    
    CREATE VIEW dbo.vseminar
    AS
      SELECT * FROM dbo.seminar;
    GO  
    
    
    CREATE PROCEDURE [dbo].[sp_seminarPaging1]               
       @pageNo int = 1,
       @ItemsPerPage int = 20,
       @NEU bit = NULL,
       @BS bit = NULL,
       @CH bit = NULL,
       @sort varchar(20) = 'beginn',
       @search varchar(255) = '%',
       @debug bit = 1,    
       
       -- 1 = Anzahl liefern
       @gettotalRows bit = 0,
       @totalRows int = null OUT
    AS         
      SET NOCOUNT ON;                    
    
      DECLARE @SQL nvarchar(max), 
        @paramlist nvarchar(1000);
      DECLARE @sicht sysname= N'vSeminar';
    
      DECLARE 
        @StartIdx int,
        @EndIdx int;
    /*    
      DECLARE @haswhere bit,
        @SQL_Conditions nvarchar(max), 
        @spalten varchar(300) = '';
    */
      
      IF @PageNo < 1 SET @PageNo = 1
      IF @ItemsPerPage < 1 SET @ItemsPerPage = 10
    
      SET @StartIdx = (@PageNo -1) * @ItemsPerPage + 1
      SET @EndIdx = (@StartIdx + @ItemsPerPage) - 1
    
      DECLARE @partitionorder nvarchar(1024);
    
      -- OVER Klausel
      SET @partitionorder = N'beginn ASC'
      IF ISNULL(@sort, 'beginn') <> 'beginn'
      BEGIN
        SET @partitionorder = QUOTENAME(@sort) + N',' + @partitionorder
      END
    
      -- einmalig '%'
      IF @search <> '%'
        SET @search = '%' + ISNULL(@search, '') + '%'
    
      SET @SQL = N'
        WITH rsSeminar AS
        (
          SELECT kursid, CONVERT(char(10), Beginn, 104) AS Datum, themen,NEU,BS,CH,kat,zert,';
          
      SET @SQL = @SQL 
        + CASE @sort      
          WHEN 'beginn' THEN N'DATENAME(MM, beginn) + '' '' + CAST(YEAR(beginn) AS VARCHAR(4))'
          WHEN 'kat' THEN N'kat'
          WHEN 'usort' THEN N'detail'
          ELSE N'detail' END 
        + ' AS sortvar';
    
      SET @SQL = @SQL + N'
          FROM (SELECT
             ROW_NUMBER() OVER(ORDER BY ' + @sort + N') AS Row, * 
          FROM ' + @sicht + N'
          WHERE (themen like @search OR beschreibung like @search OR kurztext like @search)
        ) AS tbl';
        
      IF @gettotalRows = 0
      BEGIN
        SET @SQL = @SQL + N'
        WHERE Row >= @StartIdx AND Row <= @EndIdx';
      END;
    
      -- weitere Kriterien...
      
      SET @SQL = @SQL + N')';
    
      IF @debug = 1 PRINT @sql;
    
      SET @paramList = N'@pageNo int, @ItemsPerPage int, @search varchar(257), @StartIdx int, @EndIdx int';
    
      IF @gettotalRows = 1
      BEGIN
        SET @SQL = @SQL + N'
          SELECT @TotalRows = COUNT(*) FROM rsSeminar;';
    
        SET @paramlist = @paramlist + N', @totalRows int output';
    
        EXEC sp_executesql @sql, @paramlist,
          @pageNo,
          @ItemsPerPage,
          @search,
          @StartIdx,
          @EndIdx,
          @totalRows OUT;
      END ELSE BEGIN
        SET @SQL = @SQL + N'
          SELECT * FROM rsSeminar;';
    
        EXEC sp_executesql @sql, @paramlist,
          @pageNo,
          @ItemsPerPage,
          @search,
          @StartIdx,
          @EndIdx;
      END;
      RETURN 0;
    GO
    
    -- als geteilter Aufruf
    DECLARE @totalrows int;
    
    EXEC [dbo].[sp_seminarPaging1]               
         @pageNo = 5,
         @ItemsPerPage = 20,
         @NEU = NULL,
         @BS = NULL,
         @CH = NULL,
         @sort = 'beginn',
         @search = '%',
         @debug = 1;
    
    EXEC [dbo].[sp_seminarPaging1]               
         @NEU = NULL,
         @BS = NULL,
         @CH = NULL,
         @sort = 'beginn',
         @search = '%',
         @debug = 1,
         @gettotalrows = 1,
         @totalrows = @totalrows OUT
    SELECT @totalrows AS Rows     
    
    Gruß Elmar

     

    Mittwoch, 9. Juni 2010 08:21
  • Lieber Elmar,

    vielen Dank für die Mühe und auch für die Anregungen. Ich kann es kaum fassen. :)

    Ich habe es auch ausprobiert und es läuft super schön. Allerdings ist mir nicht so richtig klar, wie ich den doppelten Aufruf umsetzen kann. Ich müsste somit in ASP.NET das ganze Verbindungsprozedure doppelt ausführen?

    Das verstehe ich jetzt nicht so richtig, tut mir leid. Ich würde natürlich liebend gerne ein schnelles sichers Scirpt verwenden. Ich sitze da nämlich jetzt schon mehr als eine Woche dran und bekomme bald die ganz dunkelrote Karte, wenn ich jetzt nicht aus den Puschen komme. Ich bin leider keine routinierte Programmiererin, weder in TSQL noch in ASP.NET ;(

    Meine Prozedur sieht wie folgt aus. Sie läuft auch. An Datensätzen habe ich nicht viel zu verwalten, aber die sind alle so kompliziert verknüpft und in vielen Kategorien und Unterkategorien verteilt, das macht den Aufbau für mich jetzt sehr schwierig.

    Ich würde es schon sehr gerne umsetzen, so wie Du es vorschlägst, aber vorerst muss ich meines verwenden. Würdest Du da nochmal drüber schauen, ob es eine Sicherheitslücke gibt?
    USE [ptsService]
    GO
    /****** Object:  StoredProcedure [dbo].[spx_PagerN]    Script Date: 06/09/2010 17:41:39 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[spx_PagerN]                             
              @PageNo int = 1,
              @ItemsPerPage int = 20,
              @kat varchar(10) = '%',
              @NEU bit = NULL,
              @BS bit = NULL,
              @CH bit = NULL,          
              @sort varchar(20) = 'beginn',
              @debug bit = 0,
              @search varchar(255) = '%',
              @detailid int = null,
              @buchid int = null,
              @kursid int = null,
              @buch int = null,
              --@zert int = null,
              @ks varchar(10) = null,
              @TotalRows int out
              
     
    AS
        BEGIN
        SET NOCOUNT ON
        DECLARE                                        
        @sql nvarchar(4000),  
        @sicht nvarchar(30),
        @where nvarchar(1000),
        @paramlist nvarchar(1000),
        @spalten nvarchar(100) = ',''0'' as detailtext',
        @haswhere bit

        

    set @sicht = 'vSeminarGesamt'

    if @detailid > 0
            BEGIN
            set @sicht = 'vSeminarDetailGesamt'
                    set @spalten = ',detail, dDetail, usort,cdetailid, detailtext '
            END
    if @buchid >0
        BEGIN
            set @sicht = 'vSeminarBuch'
            set @spalten = ',buchid, thema, verlagName '
        END

    set @where = ' where beginn >=getdate() and '

     IF @kursid > 1   
       
        BEGIN
        set @PageNo = 1
        set @ItemsPerPage = 500
            SET @where = @where + 'kursid like '+QUOTENAME(@kursid,'''')
        END
    ELSE
        Begin
        set @where = @where + '(themen like ' + quotename('%' + @search + '%','''')+ '
            or beschreibung like ' + quotename('%' + @search + '%','''')+ '
            or kurztext like ' + quotename('%' + @search + '%','''')+ ')
            and dokstatus <=2'   
      IF @detailid > 0
        BEGIN
            SET @where = @where + ' and cdetailid like '+QUOTENAME(@detailid,'''')
                                          
        END
     
     SET @hasWhere = 0
        IF @BS <> 0
        BEGIN
           SET @where = @where + ' and (BS=1'
           SET @hasWhere = 1
        END

    IF @ks <> '0'
        BEGIN
           IF @hasWhere = 0
                BEGIN
                    SET @where = @where + ' and (kontaktstudium <> "0"'
                    SET @hasWhere = 1
                end
           ELSE
                SET @sql = @sql + ' and kontaktstudium <> "0"'                       
        END
        
        IF @NEU <> 0
        BEGIN
           IF @hasWhere = 0
                BEGIN
                    SET @where = @where + ' and (NEU=1'
                    SET @hasWhere = 1
                end
           ELSE
                SET @where = @where + ' and NEU=1'                       
        END
            
        IF @CH <> 0
        BEGIN
           IF @hasWhere = 0
                BEGIN
                   SET @where = @where + ' and (CH=1'
                   SET @hasWhere = 1
                END                
            ELSE
              SET @sql = @sql + ' and CH=1'                        
        END

        IF @hasWhere = 1
        Begin
            SET @where = @where + ')'
        END    
    END

    SET @sql = 'SET QUOTED_IDENTIFIER OFF
    WITH rsContacts as
    (
       SELECT distinct ROW_NUMBER() OVER(ORDER BY ' + @sort +',beginn ASC)
                                AS [RowNr],'
       if @sort = 'beginn'
            BEGIN
                set @sql = @sql + 'DATENAME(MM, beginn) + '' '' + CAST(YEAR(beginn) AS VARCHAR(4))'
            END
        ELSE IF @sort = 'kat'
            Begin
                set @sql = @sql + 'kat'
            END
        ELSE IF @sort = 'usort'
            Begin
                set @sql = @sql + 'detail'
            END
        ELSE
            BEGIN
                set @sql = @sql + 'detail'
            END
        set @sql = @sql + ' AS sortvar,
      kursid, CONVERT(char(10), Beginn, 104) AS Datum, themen,kontaktstudium,NEU,BS,CH,kat,
      buch,zert,kTitel, detailid '+@spalten +'
      FROM ' + @sicht+ @where +') '


    SET @sql = @sql + '
    SELECT distinct * FROM rsContacts
    WHERE RowNr BETWEEN (@PageNo - 1) * @ItemsPerPage + 1
        AND @PageNo * @ItemsPerPage'  
        
                                                      
    SET @paramList = '@PageNo int,
                      @ItemsPerPage int'                                           


    IF @debug = 1 PRINT @sql
            
    EXEC sp_executesql
            @sql,
            @paramlist,
            @PageNo,
            @ItemsPerPage

            
    SET @SQL = 'SELECT @TotalRows=COUNT(*) FROM '+@sicht+@where
        EXEC sp_executesql
            @query = @SQL,
            @params = N'@TotalRows INT OUTPUT',
            @TotalRows = @TotalRows OUTPUT         
    END
    Liebe Grüße, die Luzie!
    Mittwoch, 9. Juni 2010 16:39
  • Hallo Luzie,

    wenn Du eine Verbindung offen hast, kannst Du zwei Aufrufe
    hintereinander absetzen und da die Paramter gleich sind, reicht
    eine (Sql)Command Instanz - wobei Du zuerst @TotalRows abfragen
    speichern solltest. Bei weiteren Fragen dazu => ASP.NET Forum,
    wobei Du den derzeitigen Zugriff erläutern solltest - Stefan und Co.
    können dazu mehr sagen als ich (der nicht sonderlich webaffin ist).

    Du kannst es (und ich würde es auch) stückweise umbauen, 
    um vorhandene Funktionalität nicht aus Versehen zu "demolieren".

    So wäre ein erster Schritt, Parameter (wie bei @search) einzusetzen.
    Zum Sicherheitsrisiko kann ich nur wenig sagen, da ich nicht weiß,
    welcher der Parameter von aussen hereingegeben wird -
    bei @search dürfte es der Fall sein. Denen muß man besondere
    Aufmerksamkeit schenken, was nur über den eigenen Code gesetzt
    werden kann, ist weniger anfällig.

    Zudem solltest Du das "DISTINCT" in den SELECT Klasuel versuchen
    zu elemenieren, das widerspricht sich mit ROWCOUNT.

    Aus Sicht der Wartbarkeit würde ich die Prozedur (intern) in mehrere
    auftrennen, was die Abrufe der unterschiedlichen Sichten (vSeminarBuch,
    vSeminarDetailGesamt) angeht. Langfristig blickt man erfahrungsgemöß
    sonst nur noch schwer durch, was wo benötigt wird und es schleichen sich
    Fehler (oder toter Code) ein.

    Gruß Elmar

     

    Mittwoch, 9. Juni 2010 17:13
  • Hallo Elmar,

    Vielen Dank für die Info. Ich würde es ja gerne versuchen und meinen Bedingungen anpassen, das denke ich, schaffe ich. Die unterschiedlichen Sichten in mehrere Prozeduren auszulagern, macht eigentlich keinen Sinn. Das käme nur einem Kopieren der Prozedur gleich. Die Unterschieldichkeit liegt nur ein ein oder 2 Spaltennamen.

    > wenn Du eine Verbindung offen hast, kannst Du zwei Aufrufe
    > hintereinander absetzen und da die Paramter gleich sind, reicht
    > eine (Sql)Command Instanz - wobei Du zuerst @TotalRows abfragen
    > speichern solltest.

    Ich habe das in einer Instanz jetzt auch nicht geschafft, ich wüsste auch nicht mit welcher Syntax. Bei einer Insert-Anweisung kann ich einen Output-Parameter direkt dahinter selectieren, aber bei einer gespeicherten Prozedur? Auch die Google-Suche brachte nir nicht viel. Ich denke, mit @gettotalrows ist ja doch eine Unterschiedlichkeit da, welche ich jetzt auch nicht abzufragen wüsste.

    >Bei weiteren Fragen dazu => ASP.NET Forum,
    > wobei Du den derzeitigen Zugriff erläutern solltest - Stefan und Co.
    > können dazu mehr sagen als ich (der nicht sonderlich webaffin ist).

    Hmm, das möchte ich jetzt lieber nicht.
    Ich finde es schon mehr als nett, dass Du Dich in die Prozedur reindenkst.

    Letztendlich kann ich auch mit 2 Instanzen leben, es ich ja alles noch überschaulich.

     Dim sda As New SqlDataAdapter()
            Dim cmd As New SqlCommand("sp_seminarPaging2")
            cmd.CommandType = CommandType.StoredProcedure
            cmd.Parameters.Add("@PageNo", SqlDbType.Int).Value = PageNo
            cmd.Parameters.AddWithValue("@sort", sort)
            cmd.Parameters.AddWithValue("@search", search)
            cmd.Parameters.Add("@ItemsPerPage", SqlDbType.Int).Value = ItemsPerPage
            cmd.Connection = con

            Dim sda1 As New SqlDataAdapter()
            Dim cmd1 As New SqlCommand("sp_seminarPaging2")
            cmd1.CommandType = CommandType.StoredProcedure
            cmd1.Parameters.AddWithValue("@search", search)
            cmd1.Parameters.AddWithValue("@gettotalRows", 1)
            cmd1.Parameters.Add("@TotalRows", SqlDbType.Int).Direction = ParameterDirection.Output
            cmd1.Connection = con
            Try
                con.Open()
                sda.SelectCommand = cmd
                sda1.SelectCommand = cmd1
                sda1.Fill(dt)
                sda.Fill(dt)
                DataList1.DataSource = dt
                DataList1.DataBind()
                TotalRows = Convert.ToInt32(cmd1.Parameters("@TotalRows").Value)

    Grundsätzlich läuft das so mit den 2 Instanzen. Ich werde dass jetzt mal Schritt für Schritt umbauen.

    Aber ich hätte da noch eine Frage zu dem @search Parameter bzgl. meiner alten Prozedur.

    Ich habe die Variable abgefragt

    IF @search <> '%'
        SET @search = '%' + ISNULL(@search, '') + '%'
       
    dann in die Bedingung eingebaut

    set @where = @where + '
            (themen like @search or beschreibung like @search or kurztext like @search)
            and dokstatus <=2'
           
    Weiterhin der @parmalist hinzugefügt
    und im EXEC auch ausgeben
    SET @paramList = '@PageNo int,
                      @ItemsPerPage int,@search varchar(255)'                                          


    IF @debug = 1 PRINT @sql
           
    EXEC sp_executesql
            @sql,
            @paramlist,
            @search,
            @PageNo,
            @ItemsPerPage

    Und trotzdem komme folgende Fehlermeldung:

    Meldung 8114, Ebene 16, Status 5, Zeile 0
    Fehler beim Konvertieren des varchar-Datentyps in int.
    Meldung 137, Ebene 15, Status 2, Zeile 2
    Die '@search'-Skalarvariable muss deklariert werden.

    Was soll diese Meldung sagen? Ich konvertiere sie nicht und sie ist deklariert.


    Liebe Grüße, die Luzie!
    Donnerstag, 10. Juni 2010 17:12
  • Hallo Luzie,

    wenn Du für das Hauptergebnis einen SqlDataAdapter verwendest, ist der Einsatz
    von zwei SqlCommand Instanzen sinnvoller. Um den Ausgabeparameter zu erhalten,
    benötigst Du keinen DataAdapter.  Ein ExecuteNonQuery für das SqlCommmand
    und abrufen des Parameters ("@TotalRows") danach reicht, siehe
    Ändern von Daten mit gespeicherten Prozeduren (ADO.NET)
    (das hier nichts geändert wird ist dafür ohne Belang).

    Was den Fehler bei der Parameterübergabe angeht:
    Und die Meldung bezüglich der falschen Konvertierung resultiert daraus,
    dass versucht wird, den @search-Parameter als @PageNo zu interpretieren.

    Alle bei sp_executesql verwendeten Parameter müssen in @paramlist
    deklariert werden, und dann genau in der Reihenfolge aufgeführt werden.
    Und bei Dir ist @search der Dritte (und nicht der 1.):

    SET @paramList = '@PageNo int, @ItemsPerPage int,@search varchar(255)'                      

    Umgekehrt spielt es keine Rolle, ob der Parameter effektiv verwendet wird,
    so dass Du auch mal einige "auf Vorrat" übergeben kannst.

    Gruß Elmar

    • Als Antwort markiert Luzie Samstag, 12. Juni 2010 07:42
    Donnerstag, 10. Juni 2010 18:32
  • Hallo Elmar,

    vielen Dank für die die Links. An executeNonQuery hätte ich jetzt nicht gedacht. Ich werde mal schauen.

    Jetzt, wo Du es schreibst, ich bin vor ein paar Monaten schon mal über ein ähnliches Problem mit der Fehlermeldung gestolpert und bin daraufhin dann auch den Part mit der Reihenfolge gestoßen. Aber ich habe das total verdrängt oder vergessen. :) Wenn man es nicht immer macht.

    Vielen Dank nochmal für die Mühe und die Ausdauer mit mir.

    Ich bin so froh, dass ich ein Stück weiter bin und hoffe, dies bald als erledigt zu betrachten, bevor es mich umbringt. :)

    Schönes, sonniges Wochenende wünsche ich.


    Liebe Grüße, die Luzie!
    Freitag, 11. Juni 2010 11:15