Wie SQL Command bauen wenn viele Abfrageoptionen vom User variabel sind?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von simpelSoft.

    Wie SQL Command bauen wenn viele Abfrageoptionen vom User variabel sind?

    Hi,

    ich möchte dem User Suchoptionen für eine Tabelle geben in Form einer Textbox. Daneben ein paar Checkboxes, die definieren, welche Spalten berücksichtig werden und eine Option für "Enthält" oder "Beginnt"mit

    Die Abfrage als wie

    Quellcode

    1. Select * from table where Name Like %suche% or Anschrift Like %suche% or Ort Like %suche"


    Je nach Auswahl des Users kann die Suche auch nur den Namen, die Anschrift oder den Ort beinhaltet oder eine Kombination daraus. Auch muß es nicht immer Like %suche% lauten sondern z.B. nur suche%, wenn nach "beginnt mit" gesuch wird.

    Wie baut man derartige Optionen möglichst elegant in ein Command, ohne in der If/Then Hölle zu landen?

    Viele Grüße

    John
    Ooh - ein Query-Builder!
    Leg am besten gleich eine Klasse dafür an, das wird bisserl umfangreicher.

    Ich würde eine Art Viewmodel basteln, was ein Control mit einem Sql-Abschnitt verknüpft. Die Viewmodel bestimmt anhand des Control-Zustandes, ob und wie sein Sql-Abschnit aussieht.
    Die gesamtabfrage wird mit String.Join aus den Abschnitten aller ViewModels zusammengesetzt.

    Es ist die Hölle, aber es ist nicht die If/Then - Hölle.
    Hi John,
    ich lege mir immer eine Klasse dafür an, die ich dann aufrufe. Hier so ein Beispiel (nicht komplett alles, nur ein Auszug):

    C#-Quellcode

    1. // ----------------------------------------------------------------------------------------------------------------------
    2. // SqlSelects zusammenbauen MsSql
    3. private string GetSqlSelect(int aiArt, int aiId, string as1, string as2, string as3, string as4, DateTime adtWtStart, DateTime adtWtEnd)
    4. {
    5. String lsSql = "";
    6. String lsWhereAdd = "";
    7. String lsWhereAdd1 = "";
    8. String lsWhereAdd2 = "";
    9. String lsWhereAdd3 = "";
    10. String lsWhereAdd4 = "";
    11. String lsWhereAdd5 = "";
    12. String lsWhereAdd6 = "";
    13. String lsWhereAdd7 = "";
    14. String lsOrder = "";
    15. String lsJoin = "";
    16. // String lsGroup = "";
    17. // DateTime ldtEnd = DateTime.Today; // Heute
    18. int liYear = DateTime.Now.Year - 1;
    19. int liStandort = 0;
    20. string lsStart = (liYear.ToString()) + "-01-01";
    21. string lsEnd = (liYear.ToString()) + "-12-31";
    22. DateTime ldtStart = DateTime.Parse(lsStart); // Jahresanfang VorJahr
    23. DateTime ldtEnd = DateTime.Parse(lsEnd);
    24. DateTime ldtAdd = DateTime.MinValue;
    25. switch (aiArt)
    26. {
    27. case 1: // Art Tiere
    28. lsSql = @"SELECT id_art_tier, art_tier
    29. FROM art_tier
    30. order by gewaehlt DESC,art_tier";
    31. break;
    32. case 2: // Bestandsliste und Treeview befüllen
    33. lsSql = @"SELECT tiere.id_tier,
    34. tiere.id_art_tier,
    35. tiere.id_gender,
    36. tiere.id_mutter,
    37. tiere.id_vater,
    38. tiere.nr_de,
    39. tiere.dt_geb,
    40. RTRIM(tiere.name) as name,
    41. tiere.generation,
    42. tiere.id_art_rasse,
    43. tiere.id_art_zeugung,
    44. tiere.id_gewerk,
    45. tiere.dt_gekauft,
    46. tiere.id_import,
    47. tiere.dt_verkauft,
    48. tiere.preis_vk,
    49. tiere.preis_ek,
    50. tiere.gewicht_vk,
    51. tiere.bemerkung,
    52. tiere.id_verbleib,
    53. tiere.dt_tod,
    54. tiere.id_standort,
    55. tiere.id_kunde,
    56. tiere.id_tragend,
    57. RTRIM(art_rasse.descr) AS RasseDescr,
    58. RTRIM(art_verbleib.descr) AS VerbleibDescr,
    59. RTRIM(standort.descr) AS Standort,
    60. RTRIM(anm_kunde.firma) AS KundeFirma,
    61. RTRIM(art_gender.gender) AS Gender,
    62. RTRIM(mutter.nr_de) AS TiereMutter,
    63. RTRIM(vater.nr_de) AS TiereVater,
    64. RTRIM(mutter.name) AS TiereMutterName,
    65. RTRIM(vater.name) AS TiereVaterName,
    66. RTRIM(art_kennung.descr) AS Kennung
    67. FROM tiere
    68. LEFT JOIN art_gender ON art_gender.id_gender = tiere.id_gender
    69. LEFT JOIN standort ON standort.id_standort = tiere.id_standort
    70. LEFT JOIN art_rasse ON art_rasse.id_art_rasse = tiere.id_art_rasse
    71. LEFT JOIN art_verbleib ON art_verbleib.id_verbleib = tiere.id_verbleib
    72. LEFT JOIN anm_kunde ON anm_kunde.id_kunde = tiere.id_kunde
    73. LEFT JOIN tiere AS mutter ON mutter.id_tier = tiere.id_mutter
    74. LEFT JOIN tiere AS vater ON vater.id_tier = tiere.id_vater
    75. LEFT JOIN art_kennung ON art_kennung.id_kennung = tiere.id_kennung";
    76. lsWhereAdd = " WHERE tiere.id_art_tier = " + aiId.ToString();
    77. // Jahr
    78. if ((adtWtStart > DateTime.Parse("2005-01-01")) && (adtWtEnd == DateTime.MinValue))
    79. {
    80. lsWhereAdd1 = " And tiere.dt_geb >= \'" + adtWtStart.Year.ToString() + "-01-01\'";
    81. }
    82. // De Nummer
    83. if (tbDeNr.Text.Length > 0)
    84. {
    85. lsWhereAdd2 = " And tiere.nr_de like \'%" + tbDeNr.Text + "%\'";
    86. }
    87. // Name
    88. if (tbName.Text.Length > 0)
    89. {
    90. lsWhereAdd3 = " AND tiere.name like \'%" + tbName.Text + "%\'";
    91. }
    92. // Verkaufte Tiere zeigen
    93. if (CbxVerkauft.IsChecked == false)
    94. {
    95. lsWhereAdd4 = " AND tiere.dt_verkauft IS NULL ";
    96. }
    97. // Verstorbene Tiere zeigen
    98. if (CbxVerstorben.IsChecked == false)
    99. {
    100. lsWhereAdd5 = " AND tiere.dt_tod IS NULL ";
    101. }
    102. if (as1 == "1") // nur tragende Tiere
    103. {
    104. lsWhereAdd6 = " AND anm_tragend.id_zustand = 1";
    105. }
    106. // Standortsuche
    107. if (cbxStandortSrch.SelectedIndex > 0)
    108. {
    109. DataRowView rowview = cbxStandortSrch.SelectedItem as DataRowView;
    110. if ((rowview.Row[0] != DBNull.Value))
    111. {
    112. liStandort = Int32.Parse(rowview.Row[0].ToString());
    113. lsWhereAdd7 = " AND tiere.id_standort = " + liStandort.ToString();
    114. }
    115. }
    116. lsOrder = " Order by tiere.nr_de ASC";
    117. break;
    118. case 21: // Parents im Treeview suchen Mutter, Vater
    119. lsSql = @"SELECT id_tier, id_art_tier, id_gender, id_mutter, id_vater,
    120. nr_de, dt_geb, name, generation, id_art_rasse, id_art_zeugung,


    Dann kommt eine Klasse, die die Daten holt oder mit den DataGrids befüllt. Das fertige SQL-Statement wird übergeben (nochn Beispiel aber auch nicht komplett):

    C#-Quellcode

    1. private Int32 FetchData(string psSql, int aiArt)
    2. {
    3. Int32 liRows = 0;
    4. try
    5. {
    6. SqlConnection dbConnection = new SqlConnection(psConnect);
    7. // Pass both strings to a new SqlCommand object.
    8. // SqlCommand command = new SqlCommand(psSql, dbConnection);
    9. dbConnection.Open();
    10. switch (aiArt)
    11. {
    12. case 1: // Art der Tiere laden
    13. tblArtTier = new DataTable();
    14. sdArtTier = new SqlDataAdapter(psSql, dbConnection);
    15. sdArtTier.Fill(tblArtTier);
    16. lbTiere.ItemsSource = tblArtTier.DefaultView;
    17. liRows = lbTiere.Items.Count;
    18. break;
    19. case 2: // Daten für Tiere (Treeview befüllen)
    20. tblTiere = new DataTable();
    21. sdTiere = new SqlDataAdapter(psSql, dbConnection);
    22. sdTiere.Fill(tblTiere);
    23. DgrBestand.ItemsSource = tblTiere.DefaultView;
    24. liRows = DgrBestand.Items.Count;
    25. // Treeview befüllen
    26. liRows = PrepareTreeview();
    27. break;
    28. case 21: // Daten für Eltern (Treeview befüllen)
    29. tblParents = new DataTable();
    30. sdParents = new SqlDataAdapter(psSql, dbConnection);
    31. sdParents.Fill(tblParents);
    32. liRows = tblParents.Rows.Count;
    33. break;
    34. case 23: // Für DataGrid List Tragend gesamt
    35. tblTragendBrs = new DataTable();
    36. sdTragendBrs = new SqlDataAdapter(psSql, dbConnection);
    37. sdTragendBrs.Fill(tblTragendBrs);
    38. liRows = tblTragendBrs.Rows.Count;
    39. DgrAbkalb.ItemsSource = tblTragendBrs.DefaultView;
    40. liRows = DgrAbkalb.Items.Count;
    41. break;


    Grüße Ulf

    John422 schrieb:

    Danke, passt...


    Naja, geht schon, ist aber recht anfällig für Angriffe, muss jeder selbst entscheiden.
    Korrekt wären SQL-Parameter für die Query.
    Je nachdem, welcher Datenbank-Provider, der Zweck der Parameter ist immer identisch.

    MS-SQL: docs.microsoft.com/de-de/dotne…?view=dotnet-plat-ext-5.0
    MySQL/Maria: dev.mysql.com/doc/dev/connecto…SqlCommand_Parameters.htm
    SQLite: docs.microsoft.com/de-de/dotne…rd/data/sqlite/parameters

    simpelSoft schrieb:

    muss jeder selbst entscheiden
    Hmm - ich seh das verbissener.
    Ein Programmierer darf kein Sql-Injection-Sicherheitsloch einbauen. Solch grenzt ans kriminielle, und die Schäden, die da fahrlässig in Kauf genommen werden sind exorbitant.
    Ich würde es befürworten, wenn Software-Hersteller bei Schäden durch Sql-Injection-Angriffe haftbar gemacht würden, wegen Fahrlässigkeit.

    Sql-Injection-Angriffe sind gänzlich unnötig, und sie zu vereiteln ist keine Mehrarbeit.
    Kein Programmierer sollte eine Db-Anwendung entwickeln dürfen, ohne gelernt zu haben, wie man Sql-Injection ausschliesst.

    Bei Interesse gugge Db-Tut-Bereich.
    Im übrigen, neben dem Problem mit SQL Injections, knallt die Suche weg wenn man da nach was mit Hochkommas (') sucht. Z.b. 3/4'' Schraube, Peter's Würstchenbude, etc.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    ErfinderDesRades schrieb:

    simpelSoft schrieb:

    muss jeder selbst entscheiden
    Hmm - ich seh das verbissener.

    Ich weiß und das ist auch gut so :thumbsup: .
    Aber das Thema ist ja seit vielen jahren hier im Forum dauerpräsent und immer wieder kommen diese merkwürdig zusammengefrickelten Querys hoch, das grenzt an Beratungsresistenz.
    Wenn Jemand für sich selbst programmiert oder seine Software nicht kommerziell vertreibt, dann soll er doch frickeln wie er möchte.
    Hinweise, wie es richtig geht, haben wir ja nun mehrmals gegeben, mehr kann man nicht tun.