2

this is my first question, hopefully I do things correctly. Also to preface, I'm a programming noob tasked with developing and fixing some code where I work since the programmer we've had until now left. And if done quite well for now with my limited knowledge.

I'm trying to fix as much as possible the structure of some of the code in various programs, and part of it is converting all (or most) the SqlCommand to use parameters. Where I'm stuck is when the code is calling string variables using the ternary operator (?:) and using multiple of those strings concatenated to build the full SQL command string.

For example:

string RecogidosCoresString    = seeCORES ? " and [PICKUPTYPE] = 2 " : " ";
string RecogidosSinCoresString = seeSINCORES ? " and [PICKUPTYPE] <> 2 " : " ";
string RecogidosHolds          = seeHOLDS ? " and [PICKUPSTATUS] = 1 " : " and [PICKUPSTATUS] > 1 ";

string stringreadHeader = "SELECT * FROM [RecogidosHeader] WHERE [ENTRYDATE] >= @EntryDate1 AND [ENTRYDATE] < @EntryDate2 AND ([PICKUPNMBR] = @RecogidoID OR CUSTNMBR = @CustNumb )";

SqlCommand readHeader = new SqlCommand(stringreadHeader + RecogidosHolds + RecogidosCoresString + RecogidosSinCoresString + "Order By [PICKUPNMBR] ASC", AppsConnect);

readHeader.Parameters.Add("@EntryDate1", SqlDbType.DateTime).Value = dateTimePicker1.Value.ToShortDateString();
readHeader.Parameters.Add("@EntryDate2", SqlDbType.DateTime).Value = dateTimePicker2.Value.AddDays(1).ToShortDateString();
readHeader.Parameters.Add("@RecogidoID", SqlDbType.VarChar, 50).Value = textBox1.Text;
readHeader.Parameters.Add("@CustNumb", SqlDbType.VarChar, 50).Value = textBox1.Text;

As you can see, I've been able to replace a lot of the command with parameters, I just don't know how to implement it with the other string variables. The command above works as is, but if possible, I'd like to replace the rest of the strings with parameters instead of doing the concatenating I have currently. I have other applications using similar structures, but hopefully if I can see how to fix this one I'll be able to apply it to the rest.

Not sure if the way I have been going about it is good current practice, but I can't over-complicate it either.

The string variables get their values depending on some checkboxes' status.

Any help would be appreciated. I've seen similar questions, but I haven't been able to grasp the solutions properly, so hopefully with a personal example I'll be able to make it work.

Or, maybe it's fine as it is and I shouldn't change it?

Edit: Did a preliminary testing of the answer @pwilcox gave and it seems to be working, at the very least the SQL query is going through and I have no errors, and the results seem like the ones I'm expecting. If correct, then hopefully now I'll be able to apply this logic to the other situations that need improving.

Thanks!

  • 1
    Why are you telling it that `EntryDate1` and `EntryDate2` are `SqlDbType.DateTime` but then passing a string to it? `dateTimePicker1.Value` and `dateTimePicker2.Value.AddDays(1)` are both perfectly good `DateTime` types – Ňɏssa Pøngjǣrdenlarp Feb 20 '20 at 19:04
  • 3
    For your first question, this isn't that bad. Welcome to SO. –  Feb 20 '20 at 19:05
  • @ŇɏssaPøngjǣrdenlarp No clue why that is written that way (don't recall if it was originally like that or if I changed it for some reason). It currently works as is, but will try making those changes later and testing it out. Thanks. – MasterOfNothing Feb 20 '20 at 19:20
  • @ŇɏssaPøngjǣrdenlarp Did some testing, and the query doesn't work without the .ToShortDateString() portion for the date. Don't know why that is, but it needs it to work. – MasterOfNothing Mar 04 '20 at 18:55

1 Answers1

1

Handle the different possibilities of seeCORES, seeSINCORES and seeHOLDS with or statements inside the SQL statement itself. In reading below it may help to remember that in sql server, and is processed first before or.

string stringreadHeader = @"
    select      * 
    from        recogidosHeader
    where       entrydate >= @EntryDate1 
    and         entrydate < @EntryDate2 
    and         (pickupnmbr = @RecogidoID or custnmbr = @CustNumb)

    and         (@seeCORES = 1 and pickuptype = 2 or @seeCORES = 0)
    and         (@seeSINCORES = 1 and pickuptype <> 2 or @seeSINCORES = 0)
    and         (
                       @seeHOLDS = 1 and pickupstatus = 1
                    or @seeHOLDS = 0 and pickupstatus > 1
                )

    order by    pickupnmbr
";

...
readHeader.Parameters.Add("@seeCORES", SqlDbType.Bit).Value = seeCORES ? 1 : 0;
readHeader.Parameters.Add("@seeHOLDS", SqlDbType.Bit).Value = seeHOLDS ? 1 : 0;

I don't know if you need the ? 1 : 0 part, conversion from boolean to bit may just work with the variables as they are.

Just to note though, in your original code, I believe setting seeCORES and seeSINCORES both to true will give very similar output to setting them both to false. The only difference will be that setting them both to false will give MORE records if there are any null values in pickuptype. Is this the intended behavior? (rhetorical question).

pwilcox
  • 5,542
  • 1
  • 19
  • 31
  • Follow [this fiddle](http://sqlfiddle.com/#!18/32a49/6) to see a working example with a different schema, but using the same concept. – Vítor Martins Feb 20 '20 at 19:20
  • OK, I'll try to make sense of this and report back. Did you forget the variable seeSINCORES? Sorry, just saw what you wrote about that. – MasterOfNothing Feb 20 '20 at 19:24
  • No, that's accounted for in my narrative, but I think I can see why I might have been wrong to exclude it. Stand by while I make an edit. – pwilcox Feb 20 '20 at 19:26
  • Thanks, I'm not sure how to make it work as I want yet, so I'll see when I can test it, but I'm getting a better understanding on the logic behind it. As for your last sentence of your answer, can you elaborate a bit since I don't understand, in particular what the alternative would be ("with the variables as they are"). Sorry for my noobness. – MasterOfNothing Feb 20 '20 at 19:35
  • Well, it's just a matter of your need. But to me, it seems that the original author intended them to be switches that open up viewing for a subset of the records when turned on. So (1) if one of them is on, you see it's records, (2) if the other is on you see those instead, (3) if. both are on, you see all records, (4) and if neither is on, you see no records. I believe this last criteria (4) is violated. If both switches are off, you see all records. If this is not desired, get rid of `or @seeCORES = 0` and `or @seeSINCORES = 0`. – pwilcox Feb 20 '20 at 19:47
  • @pwilcox About seeCores and seeSINCORES being both true would be impossible as I have them to deselect each other when selected. In fact, only one checkbox can be selected at a time (which is what decides the value of the variables). If not mistaken, either all 3 of them are false or one (and only one) of them is selected. – MasterOfNothing Feb 20 '20 at 19:48
  • Sorry to bother. I'm employing this on another application, and I'm getting the results I want from SQL. But using this method is giving me a big difference in performance issues on the query. Should that be expected? I think I fixed it by changing the value being matched (first I had it matching a specific value, but now I realize I only need to find if the column is empty or not... will need to validate results). But the question remains on the expected performance. This is the portion: AND (@seePrinted = 1 AND a.[PICTICNU] = a.[SOPNUMBE] OR @seePrinted = 0 AND a.[PICTICNU] = '') – MasterOfNothing Feb 28 '20 at 20:18
  • 1
    @MasterOfNothing, there are too many open questions to answer that with much confidence. But I can advise you look at the Execution plan (SSMS -> Query -> Include Actual Execution Plan) to investigate. Also, I would say that there are a lot of `or` statements in the filtering. So if you have the ability to change how your check boxes work, where, for instance, the user can check both to see all data, one to see some of it, and none to see nothing, I think that would simplify your statement and it may very well run faster. – pwilcox Feb 28 '20 at 20:29