Ошибка при преобразовании типа данных varchar - PullRequest
5 голосов
/ 06 августа 2009

В настоящее время у меня есть таблица со столбцом varchar. Этот столбец может содержать цифры или текст. Во время определенных запросов я воспринимаю его как столбец bigint (я делаю соединение между ним и столбцом в другой таблице bigint)

Поскольку в этом поле были только цифры, проблем не возникало, но в ту минуту, когда в одной строке был текст, а не числа в этом поле, я получил сообщение «Ошибка преобразования типа данных varchar в bigint». ошибка, даже если в части WHERE я удостоверился, что ни одно из текстовых полей не появилось.

Для решения этой проблемы я создал следующее представление:

SELECT     TOP (100) PERCENT ID, CAST(MyCol AS bigint) AS MyCol
FROM         MyTable
WHERE     (isnumeric(MyCol) = 1)

Но хотя представление отображает только строки с числовыми значениями и приводит Mycol к bigint, я все равно получаю Ошибка преобразования типа данных varchar в bigint при выполнении следующего запроса:

SELECT * FROM MyView where mycol=1

При выполнении запросов к представлению он не должен знать, что происходит за ним! он должен просто увидеть два поля bigint! ( см. Прикрепленное изображение , даже в mssql management studio поля просмотра отображаются как bigint)

Ответы [ 8 ]

2 голосов
/ 10 августа 2009

OK. Я наконец создал представление, которое работает:

SELECT TOP (100) PERCENT id, CAST(CASE WHEN IsNumeric(MyCol) = 1 THEN MyCol ELSE NULL END AS bigint) AS MyCol
FROM         dbo.MyTable
WHERE     (MyCol NOT LIKE '%[^0-9]%')

Благодаря AdaTheDev и CodeByMoonlight . Я использовал ваши два ответа, чтобы добраться до этого. (Конечно, спасибо и другим ответчикам)

Теперь, когда я присоединяюсь к другим столбцам bigint или выполняю что-то вроде «SELECT * FROM MyView, где mycol = 1», он возвращает правильный результат без ошибок. Я предполагаю, что CAST в самом запросе заставляет оптимизатор запросов не смотреть на исходную таблицу, как сказал Кристиан Хейтер, возможно, с другими представлениями

1 голос
/ 06 августа 2009

Чтобы ответить на ваш вопрос о сообщении об ошибке: когда вы ссылаетесь на имя представления в другом запросе (предполагая, что это традиционное представление, а не материализованное представление), SQL Server эффективно выполняет макроопределение определения представления в запросе на потребление, а затем выполняет это.

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

Следствием этого является то, что в случае возникновения ошибки описания ошибок могут выглядеть запутанными, поскольку механизм выполнения обращается к базовым таблицам для данных, а не к представлению.

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

Сказав это, я согласен с предыдущими ответами - вам следует переосмыслить дизайн таблицы и разделить текстовые и целочисленные значения данных на отдельные столбцы.

1 голос
/ 07 августа 2009

Попробуйте изменить свой взгляд на это:

SELECT TOP 100 PERCENT ID, 
Cast(Case When IsNumeric(MyCol) = 1 Then MyCol Else null End AS bigint) AS MyCol
FROM MyTable
WHERE (IsNumeric(MyCol) = 1)
1 голос
/ 06 августа 2009

В идеале вы должны стараться избегать хранения данных в этой форме - стоило бы разбить данные BIGINT на отдельный столбец как для производительности, так и для упрощения запросов.

Однако вы можете сделать JOIN, как в этом примере. Обратите внимание, что я не использую ISNUMERIC () , чтобы определить, является ли это BIGINT действительным, потому что это проверит неправильные значения, что приведет к ошибке преобразования (например, десятичные числа).

DECLARE @MyTable TABLE (MyCol VARCHAR(20))
DECLARE @OtherTable TABLE (Id BIGINT)

INSERT @MyTable VALUES ('1')
INSERT @MyTable VALUES ('Text')
INSERT @MyTable VALUES ('1 and some text')
INSERT @MyTable VALUES ('1.34')
INSERT @MyTable VALUES ('2')
INSERT @OtherTable VALUES (1)
INSERT @OtherTable VALUES (2)
INSERT @OtherTable VALUES (3)

SELECT *
FROM @MyTable m
    JOIN @OtherTable o ON CAST(m.MyCol AS BIGINT) = o.Id
WHERE m.MyCol NOT LIKE '%[^0-9]%'

Обновление: Единственный способ найти его для работы с предложением WHERE для определенного целочисленного значения без выполнения еще одного CAST () для предположительно столбца bigint в предложении where - это использовать пользовательскую функцию:

CREATE  FUNCTION [dbo].[fnBigIntRecordsOnly]()
RETURNS @Results TABLE (BigIntCol BIGINT)
AS
BEGIN
INSERT @Results
SELECT CAST(MyCol AS BIGINT)
FROM MyTable
WHERE MyCol NOT LIKE '%[^0-9]%'
RETURN
END

SELECT * FROM [dbo].[fnBigIntRecordsOnly]() WHERE BigIntCol = 1

Не думаю, что это отличная идея с точки зрения производительности, но это решение

0 голосов
/ 06 августа 2009

Попробуйте использовать это:

SELECT 
  ID, 
  CAST(MyCol AS bigint) as MyCol
FROM
(
  SELECT TOP (100) PERCENT 
      ID, 
      MyCol 
  FROM 
      MyTable 
  WHERE 
      (isnumeric(MyCol) = 1)
) as tmp

Это должно работать, поскольку внутренний выбор возвращает только числовые значения, а внешний выбор может поэтому преобразовать все значения из первого выбора в числовой. Кажется, что в вашем собственном коде SQL пытается выполнить приведение перед выполнением isnumeric функции (возможно, это связано с оптимизацией).

0 голосов
/ 06 августа 2009

Попробуйте выполнить выборку в 2 этапа.

сначала создайте представление, которое выбирает все столбцы, в которых мой столбец числовой.

Затем сделайте выборку в том представлении, где вы разыгрываете поле varchar.

Другая вещь, на которую вы могли бы обратить внимание, - это ваш дизайн таблиц, чтобы убрать необходимость в приведении.

EDIT

  • Некоторые из чисел больше, чем bigint?
  • Есть ли пробелы, ведущие, висячие или в числе?
  • Есть ли символы формата? Десятичные знаки?
0 голосов
/ 06 августа 2009

Рассмотрите возможность создания избыточного поля bigint для хранения целочисленного значения af MyCol.

Затем вы можете проиндексировать новое поле, чтобы ускорить объединение.

0 голосов
/ 06 августа 2009

Вы пытались преобразовать поле bigint другой таблицы в varchar? Что касается меня, то имеет смысл выполнить более надежное преобразование ... Это не должно сильно повлиять на вашу производительность, если поле varchar проиндексировано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...