2

I have a Gridview in front end where Grid have two columns : ID and Order like this:

 ID        Order

 1           1
 2           2
 3           3
 4           4

Now user can update the order like in front end Gridview:

ID        Order

 1           2
 2           4
 3           1
 4           3

Now if the user click the save button the ID and order data is being sent to Stored Procedure as @sID = (1,2,3,4) and @sOrder = (2,4,1,3)

Now if I want to update the order and make save I want to store it into database. Through Stored procedure how can update into the table so that the table is updated and while select it gives me the results like:

ID        Order

 1           2
 2           4
 3           1
 4           3
Mahmoud Gamal
  • 78,257
  • 17
  • 139
  • 164

3 Answers3

1

There is no built in function to parse these comma separated string. However, yo can use the XML function in SQL Server to do this. Something like:

DECLARE @sID VARCHAR(100) = '1,2,3,4';
DECLARE @sOrder VARCHAR(10) = '2,4,1,3';

DECLARE @sIDASXml xml = CONVERT(xml,
                            '<root><s>' + 
                            REPLACE(@sID, ',', '</s><s>') + 
                            '</s></root>');

DECLARE @sOrderASXml xml = CONVERT(xml,
                        '<root><s>' + 
                        REPLACE(@sOrder, ',', '</s><s>') + 
                        '</s></root>');

;WITH ParsedIDs
AS
(
    SELECT ID = T.c.value('.','varchar(20)'),
    ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RowNumber
    FROM @sIDASXml.nodes('/root/s') T(c)
), ParsedOrders
AS
(
    SELECT "Order" = T.c.value('.','varchar(20)'),
        ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RowNumber
    FROM @sOrderASXml.nodes('/root/s') T(c)
)
UPDATE t
SET t."Order" = p."Order"
FROM @tableName AS t
INNER JOIN
(
   SELECT i.ID, p."Order"
   FROM ParsedOrders p 
   INNER JOIN ParsedIDs i ON p.RowNumber = i.RowNumber
) AS p ON t.ID = p.ID;

Live Demo

Then you can put this inside a stored procedure or whatever.

Note that: You didn't need to do all of this manually, it should be some way to make this gridview update the underlying data table automatically through data binding. You should search for something like this instead of all this pain.

Community
  • 1
  • 1
Mahmoud Gamal
  • 78,257
  • 17
  • 139
  • 164
  • Thanks a lot but what is T.c.value? – user1446764 Feb 04 '13 at 08:06
  • @user1446764 The [**`value()`**](http://msdn.microsoft.com/en-us/library/ms178030.aspx) is one of the four XML data types methods in SQL Server. It is used to extract the value inside the xml node. – Mahmoud Gamal Feb 04 '13 at 08:45
1

You could use a table valued parameter to avoid sending delimiter-separated values or even XML to the database. To do this you need to:

  1. Declare a parameter type in the database, like this:

    CREATE TYPE UpdateOrderType TABLE (ID int, Order int)
    
  2. After that you can define the procedure to use the parameter as

    CREATE PROCEDURE UpdateOrder (@UpdateOrderValues UpdateOrderType readonly)
    AS
    BEGIN
      UPDATE t
        SET OrderID = tvp.Order
        FROM <YourTable> t
          INNER JOIN @UpdateOrderValues tvp ON t.ID=tvp.ID
    END
    

    As you can see, the SQL is trivial compared to parsing XML or delimited strings.

  3. Use the parameter from C#:

    using (SqlCommand command = connection.CreateCommand()) {
      command.CommandText = "dbo.UpdateOrder";
      command.CommandType = CommandType.StoredProcedure;
    
      //create a table from your gridview data
      DataTable paramValue = CreateDataTable(orderedData) 
      SqlParameter parameter = command.Parameters
                                .AddWithValue("@UpdateOrderValues", paramValue );
      parameter.SqlDbType = SqlDbType.Structured;
      parameter.TypeName = "dbo.UpdateOrderType";
    
      command.ExecuteNonQuery();
    }
    

    where CreateDataTable is something like:

    //assuming the source data has ID and Order properties
    private static DataTable CreateDataTable(IEnumerable<OrderData> source) {
      DataTable table = new DataTable();
      table.Columns.Add("ID", typeof(int));
      table.Columns.Add("Order", typeof(int));
      foreach (OrderData data in source) {
          table.Rows.Add(data.ID, data.Order);
      }
      return table;
    }
    

    (code lifted from this question)

As you can see this approach (specific to SQL-Server 2008 and up) makes it easier and more formal to pass in structured data as a parameter to a procedure. What's more, you're working with type safety all the way, so much of the parsing errors that tend to crop up in string/xml manipulation are not an issue.

Community
  • 1
  • 1
SWeko
  • 30,434
  • 10
  • 71
  • 106
0

You can use charindex like

DECLARE @id VARCHAR(MAX)
DECLARE @order VARCHAR(MAX)

SET @id='1,2,3,4,'
SET @order='2,4,1,3,'

WHILE CHARINDEX(',',@id) > 0
BEGIN
DECLARE @tmpid VARCHAR(50)
SET @tmpid=SUBSTRING(@id,1,(charindex(',',@id)-1))
DECLARE @tmporder VARCHAR(50)
SET @tmporder=SUBSTRING(@order,1,(charindex(',',@order)-1))

UPDATE dbo.Test SET
[Order]=@tmporder
WHERE ID=convert(int,@tmpid)

SET @id = SUBSTRING(@id,charindex(',',@id)+1,len(@id))
SET @order=SUBSTRING(@order,charindex(',',@order)+1,len(@order))
END
Prashant16
  • 1,514
  • 3
  • 18
  • 39