0

I have an insert statement which creates a new row into a table:

string SQLQuery = "INSERT INTO TABLEABC VALUES('" + Rtext + "', '" + TDate + "')";

But I want to create multiple lines for 20 repeats worth of data for 8 week (56 days) intervals.

For example:

Rtext TDate
John  23/11/2018

I would want it to create:

Rtext TDate
John  23/11/2018
John  18/01/2019
John  15/03/2019
John  10/05/2019
John  05/07/2019
John  30/08/2019
John  25/10/2019
John  20/12/2019
John  14/02/2020
John  10/04/2020
John  05/06/2020
John  31/07/2020
John  25/09/2020
John  20/11/2020
John  15/01/2021
John  12/03/2021
John  07/05/2021
John  02/07/2021
John  27/08/2021
John  22/10/2021
John  17/12/2021
6
  • Recursive cte? Add 56 days for each iteration. Commented Nov 23, 2018 at 8:50
  • 1
    What's wrong with just using DateTime.AddDays(56) in a loop from 1 to 20? Commented Nov 23, 2018 at 8:51
  • Use TDate.AddDays(56) and assign parameters for every execution. Don't forget to use Parameters.Clear(). Commented Nov 23, 2018 at 8:51
  • @jarlh liek this? DECLARE @i int = 0 WHILE @i < 300 BEGIN SET @i = @i + 1 /* your code*/ END Commented Nov 23, 2018 at 8:54
  • Why are you not parametrising your query either? This is wide open to SQL injection. Personally, I would handle the additional rows in SQL Server as well; either by use of an rCTE (as @jarlh mentioned) or a (virtual) tally table. Commented Nov 23, 2018 at 8:54

4 Answers 4

2

Firstly, you should be parametrising your query. My C# is very rusty (poor), so you'll have to excuse me if this is wrong, however, if I recall (and my Google-fu worked), then you'll want to do something more like:

string SQLQuery = "INSERT INTO TABLEABC VALUES(@RText, @TDate)";
SQLCommand Command = new SQLCommand(SQLQuery, YourConnection);
Command.Parameters.Add("@RText",SQLDbType.varchar);
Command.Parameters["@RText"].Value = RText; //Assumed variable name
Command.Parameters.Add("@TDate",SQLDbType.date); //Assumed datatype
Command.Parameters["@TDate"].Value = TDate; //Assumed variable name

This doesn't solve the repeating items though, so the first line could be replaced with:

string SQLQuery = "INSERT INTO TableABC SELECT @RText, DATEADD(WEEK, 8*I, @TDate) FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19)) V(I);";

Alternativey, you could use a rCTE instead of a virtual Tally table. In SQL this would look like:

WITH rCTE AS(
        SELECT @RText AS RText,
               @TDate AS TDate
               0 AS I
        UNION ALL
        SELECT RText,
               DATEADD(WEEK, (I+1)*8,TDate) AS TDate,
               I+1
        FROM rCTE
        WHERE I+1 <20
)
INSERT INTO TABLEABC
SELECT RText,
       TDate
FROM rCTE;

If you're going to have a large amount of values, a scalable Tally Table is the way to go:

WITH N AS(
        SELECT N
        FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1 -10
         CROSS JOIN N N2 --100
         CROSS JOIN N N2 --1000
         CROSS JOIN N N2 --10000 --you get the idea
    )
INSERT INTO TABLEABC
SELECT TOP 500
       @RText,
       DATEADD(WEEK, (I-1)*8, @TDate)
FROM Tally;

A rCTE, in the sense above, is an RBAR method, so it's speed will get slower the more rows you need. A tally table would be far faster, isn't RBAR, and doesn't need the MAXRECURSION option.

Sign up to request clarification or add additional context in comments.

6 Comments

While this may be correct, would you do the same if we wanted to insert 500 values instead of 20?
@Rafalon The OP specifically states 20 in their post. For 500 I would use a scalable tally table,.
Don't take offense, my question was only here to make you think further and improve your (already good) answer :)
Added a Scalable Virtual Tally Table for you @Rafalon
Can you put this into a full answer? I dont know which parts need using
|
1

Looking into the syntax you are using, seems like you are trying it in C#. So use below code.

you need to use stringbuilder and append insert string or concate in SQLQuery. Use below code.

Datetime myDate = Convert.toDatetime("23/11/2018")
string SQLQuery = "INSERT INTO TABLEABC VALUES('" + Rtext + "', '" + TDate + "');";
SQLQuery += "INSERT INTO TABLEABC VALUES('" + John  + "', '" + myDate + "');";

for (int i = 1; i <=19; i++)
{
      SQLQuery +=" INSERT INTO TABLEABC VALUES('" + John  + "', myDate.AddDays(56) );";
}

11 Comments

Injection is still a problem here.
what are you using for injecting in database? is it linq or entity-relational mapping?
How about Rtext = "1','19000101'); DROP TABLE TABLEABC;--"?
Is Rtext name of column ? what is '19000101'?
@AgustusCodes the very fact that you do not know what Rtext is when you have it in your answer kind of invalidates your answer
|
1

I preferred using SQL parameters and a for loop to execute the insert command for every iteration, but you should clear parameters before next execution begins. Here is an example by assumed that you're converting the date string to DateTime first:

string SQLQuery = "INSERT INTO TABLEABC (RText, TDate) VALUES (@RText, @TDate)";

// edit: TDate is a string, convert it to DateTime first
DateTime date;

if (DateTime.TryParseExact(TDate, "dd/MM/yyyy", CultureInfo.InvariantCulture, 
    DateTimeStyles.None, out date)
{
    using (var con = new SqlConnection(connectionString))
    {
        con.Open();
        using (var cmd = new SqlCommand(SQLQuery, con))
        {
            for (var i = 0; i < 20; i++)
            {
                cmd.Parameters.AddWithValue("@RText", Rtext);

                // add for next iterations
                if (i > 0)
                {
                    date = date.AddDays(56);
                }

                cmd.Parameters.AddWithValue("@TDate", date);

                cmd.ExecuteNonQuery();
                cmd.Parameters.Clear(); // clear existing parameters for next iteration
            }
        }
    }
}
else
{
    // handle invalid dates
}

Note: If the data type is exactly known, use Parameters.Add() instead of Parameters.AddWithValue().

14 Comments

Getting an error: 'string' does not contain a definition for 'AddDays' and no accessible extension method 'AddDays' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)
Because you have date stored as string in TDate maybe?
Yes string TDate= TDateTB.Text;
AddDays is used for DateTime. If you want to convert a string to DateTime, use var date = DateTime.ParseExact(TDate, "dd/MM/yyyy", CultureInfo.InvariantCulture) and use date inside Add()/AddWithValue().
hmm getting The name 'CultureInfo' does not exist in the current context now
|
0

You can try this.

DECLARE @i INT=0, @LastDate AS DATE=GETDATE()

WHILE (@i < 20)
BEGIN
    INSERT INTO TABLEABC VALUES('" + Rtext + "', '" + @LastDate + "')

    SET @LastDate = @LastDate.AddDays(56)
    SET @i=@i+1;
END

5 Comments

This won't work as is, you have to consider the fact that it is inside c# code. Double-check your quotation marks ;) Also this won't prevent SQL-injection. Plus, does SQL really support .AddDays(56)?
Looping is not great inside SQL Server, and this doesn't address to injection issue at all.
What does AddDays(56) do in SET @LastDate = @LastDate.AddDays(56)? is this a new function in SQL Server?
@Sami Initial value of '@LastDate is today's date. '@LastDate.AddDays(56) means we are adding 56days to the '@LastDate.
@ThilinaNakkawita, that's great, if the code you've got in your answer was in a language that supported that syntax. What you've got here is a weird hybrid of C# and SQL, which will run in neither

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.