mekenix Ответов: 1

Как точно выбрать между двумя значениями даты?


Привет. Я хочу создать поиск для моих дат входа, и я написал эту строку кода.

private void History()
        {
            int i = 0;
            dataGridView1.Rows.Clear();
            cn.Open();
            cm = new SqlCommand("select * from vwStockIn where cast(sdate as date) between @sdate and @sdate1 and status like 'Bitti'", cn); 
            cm.Parameters.AddWithValue("@sdate", dt1.Value.ToShortDateString());
            cm.Parameters.AddWithValue("@sdate1", dt2.Value.ToShortDateString());

            dr = cm.ExecuteReader();
            while (dr.Read())
            {
                i++;
                dataGridView1.Rows.Add(i, dr[0].ToString(), dr[1].ToString(), dr[2].ToString(), dr[3].ToString(), dr[4].ToString(), dr[5].ToString(), dr[6].ToString());
            }
            dr.Close();
            cn.Close();
        }


Теперь это очень шатко. Иногда он показывает мне время, которое я хочу, а иногда просто показывает все, иногда он дает ошибку, потому что я ставлю номер дня выше 12. может быть, это потому, что я думаю об этом как о европейской вещи времени, потому что только когда я нажимаю 13 и пытаюсь искать, он дает мне следующую ошибку .

System.Data.SqlClient.SqlException: 'Conversion failed when converting date and/or time from character string.'



Даже если я избавился от этой ошибки, все равно остается огромная проблема.Это ненадежно.Он никогда не показывает мне то, что я хочу, но показывает все остальное.Есть ли способ, чтобы я мог получить последовательные и точные даты? Я имею в виду, когда я нажимаю 01:09:2020 - 10:09:2020 и поиск его у меня есть данные в sql, которые находятся в 01:09:2020, но он не показывает мне этот, но он показывает мне тот, который находится в 18:09:2020, например, что происходит?

Что я уже пробовал:

Я подумал, что, возможно, проблема в том, что я попытался написать его с параметрами, и я попытался написать его так

cm = new SqlCommand("select * from vwStockIn where cast(sdate as date) between '" + dt1.Value.ToShortDateString() + "' and '" + dt2.Value.ToShortDateString() + "' and status like 'Done'", cn);


Кроме того, я пробовал писать его без приведения строки(sdate as date) и заменял ее просто sdate, но это тоже не имело никакого значения

mekenix

Я думаю,что проблема заключается в том,что microsoft sql ожидает значение dd,MM,yyyy, в то время как visual studio c# дает значение MM, dd, yyyy, но я не уверен. Даже если бы это была проблема, я понятия не имею, как ее исправить, поэтому мне нужна помощь :D

1 Ответов

Рейтинг:
9

OriginalGriff

Никогда не делай этого:

cm = new SqlCommand("select * from vwStockIn where cast(sdate as date) between '" + dt1.Value.ToShortDateString() + "' and '" + dt2.Value.ToShortDateString() + "' and status like 'Done'", cn);

Никогда не объединяйте строки для построения команды SQL. Это оставляет вас широко открытыми для случайной или преднамеренной атаки SQL-инъекции, которая может уничтожить всю вашу базу данных. Вместо этого всегда используйте параметризованные запросы.

Когда вы объединяете строки, вы вызываете проблемы, потому что SQL получает такие команды, как:
SELECT * FROM MyTable WHERE StreetAddress = 'Baker's Wood'
Цитата, добавленная пользователем, завершает строку в том, что касается SQL, и вы получаете проблемы. Но могло быть и хуже. Если я приду и наберу вместо этого: "x';DROP TABLE MyTable;--", то SQL получит совсем другую команду:
SELECT * FROM MyTable WHERE StreetAddress = 'x';DROP TABLE MyTable;--'
Которые SQL видит как три отдельные команды:
SELECT * FROM MyTable WHERE StreetAddress = 'x';
Совершенно правильный выбор
DROP TABLE MyTable;
Вполне допустимая команда "удалить таблицу"
--'
А все остальное-это комментарии.
Так оно и происходит: выбирает любые совпадающие строки, удаляет таблицу из базы данных и игнорирует все остальное.

Поэтому всегда используйте параметризованные запросы! Или будьте готовы часто восстанавливать свою БД из резервной копии. Вы ведь регулярно делаете резервные копии, не так ли?

Не делай этого:
cm.Parameters.AddWithValue("@sdate", dt1.Value.ToShortDateString());
cm.Parameters.AddWithValue("@sdate1", dt2.Value.ToShortDateString());
Это просто вводит слой дополнительной сложности, когда вы преобразуете в строку на основе настроек Вашего компьютера, а SQL преобразует обратно в дату на основе его настроек.
Вместо этого передайте значение DateTime напрямую:
cm.Parameters.AddWithValue("@sdate", dt1.Value);
cm.Parameters.AddWithValue("@sdate1", dt2.Value);
И никакие преобразования не требуются.
Если, конечно, ваш столбец БД не хранит информацию о дате в столбце VARCHAR или NVARCHAR вместо DATE, DATETIME или DATETIME2, то в этом случае вам нужно изменить ее, иначе ваши сравнения все равно не будут работать корректно.

Затем посмотрите на остальную часть вашего SQL:
cm = new SqlCommand("select * from vwStockIn where cast(sdate as date) between @sdate and @sdate1 and status like 'Bitti'", cn);

LIKE-это оператор, который нуждается в подстановочных знаках: без них он идентичен"=", но медленнее.
Ты можешь попробовать:
...LIKE '%Bitti%
который найдет все, что имеет в себе "Битти".

Тогда это меня беспокоит:
...WHERE CAST(sdateAS DATE)...
что подразумевает, что вы являются хранение информации о дате в столбце VARCHAR или NVARCHAR, и это плохая идея, потому что когда вы пытаетесь использовать ее, вам нужно преобразовать ее в дату, чтобы сделать что - нибудь-если вы этого не сделаете, то используется сравнение на основе строк, и это дает результат исключительно на основе первой пары различных символов. Это означает, что сортировка и сравнение не используют порядок дат: 01-12-2020 - это до 31-01-2000. И... он полагается на то, что ваши данные никогда не получают "плохих данных", что маловероятно, и включает в себя каждый компьютер, вставляющий информацию о дате, используя одни и те же настройки ...
Если да, то измените свою БД


mekenix

Нет, моя информация о дате находится в столбце типа datetime. Я думал, что каким-то образом sql не думал, что это дата, поэтому попытался преобразовать ее просто для безопасности, но это не имело никакого значения.

а что если я сделаю вот так

cm = new SqlCommand("select * from vwStockIn where sdate between @sdate and @sdate1 and status like 'Bitti'", cn);
см.параметры.AddWithValue("@sdate" ,DateTime.Синтаксический анализ(ст1.Значение.ToShortDateString()));
см.параметры.AddWithValue("@sdate1",DateTime.Синтаксический анализ(ст2.Значение.ToShortDateString()));


в чем была бы проблема, если бы я написал это так? Кроме ненужного использования тошортдатестринга.


Следующий вопрос, давайте подумаем о гипотетическом сценарии. Я ищу запись, которая находится в 10:09:2020. Я ищу его, выбирая даты 09:09:2020 и 10:09:2020. Но моя программа не показывает мой рекорд. Или если я выберу 10:09:2020 и 10:09:2020, которые все равно ничего не показывают. Но это работает, когда я выбираю 10:09:2020 и 11:09:2020 Как я могу исправить эту проблему?

OriginalGriff

Зависит: Я предполагал, что dt1 и dt2 были DateTimePickers - в этом случае свойство Value уже является DateTime и может быть передано непосредственно SQL в качестве параметра. Если это не так, то вам нужно использовать DateTime.Попробуйте проверить и преобразовать его в верхней части вашего метода и продолжить только в том случае, если пользователь набрал правильно.

И как будто *все еще* нуждается в подстановочных знаках!

mekenix

Спасибо за вашу помощь, сэр. :)