Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Привет. Намедни ко мне пришёл очень уважаемый мной Sulorhiw, с очень офигевшим лицом.
Причину своего состояния он описал на SQL. Вот смотрите: сделаем два представления:
CREATE VIEW foo as SELECT f1 = 1;
GO
CREATE VIEW bar 
AS
SELECT	
	f1
FROM
	(	SELECT f1 = 1 
		UNION 
		SELECT f1 = 2
	)	dt 
WHERE 
	f1 IN (SELECT f1 FROM foo);
GO

"SELECT * FROM foo;" естественно вернёт одну запись с f1 = 1.
Теперь изменим foo:
ALTER VIEW foo as SELECT b1 = 1;

После этого, казалось бы, bar должна перестать работать. Однако "SELECT * FROM bar;" вместо того чтоб бросать исключения, спокойно работает, но теперь возвращает обе записи f1 = 1 и f1 = 2. Причём просто запрос:
SELECT	
	f1
FROM
	(	SELECT f1 = 1 
		UNION 
		SELECT f1 = 2
	)	dt 
WHERE 
	f1 IN (SELECT f1 FROM foo);

также будет работать.

Увы это не баг. В настоящих языках программирования, это называется затенение имени. Суть в том, что в первом случае, имя поля foo.f1 в подзапросе "(SELECT f1 FROM foo)" "затеняет" имя поля dt.f1 внешнего запроса. А во втором случае поля с именем f1 в bar уже нет, и используется поле dt.f1 из внешнего запроса. Фактически "(SELECT f1 FROM foo)" превращается в "(SELECT @BarValue FROM foo)", где @BarValue равно текущему (подзапрос для каждой записи dt выполняется) значению dt.f1. Это наглядно видно если выполнить такой запрос:
CREATE VIEW foo as SELECT f1 = 1;
GO
SELECT	
	f1
,	b1 = (SELECT f1 FROM foo)
FROM
	(	SELECT f1 = 1 
		UNION 
		SELECT f1 = 2
	)	dt 
GO
ALTER VIEW foo as SELECT b1 = 1;
GO
SELECT	
	f1
,	b1 = (SELECT f1 FROM foo)
FROM
	(	SELECT f1 = 1 
		UNION 
		SELECT f1 = 2
	)	dt 
GO


Чтоб не попадать в такие ситуации, лично я использую псевдонимы для имён таблиц во всех многотабличных запросах, и обязательно использую в выражениях полное имя поля "<таблица или псевдним>.<поле>". ...чего и вам советую.
4 мар 14, 13:13    [15669205]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
Вот смотрите: сделаем два представления:

Начать надо с полной версии сервера
4 мар 14, 13:14    [15669219]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
Во-вторых, константы - это не таблицы. Ваш пример для таблиц работает ?
В-третьих, вы план выполнения смотрели ?
4 мар 14, 13:16    [15669240]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
ZOOKABAKODER, но, вообще-то, это древний-предревний баян!
И эффект этот мы тут очень часто используем.
4 мар 14, 13:27    [15669328]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Glory,

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

Версия сервера не при чём. IMHO
4 мар 14, 13:31    [15669363]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
ZOOKABAKODER,

и я совершенно не согласен с Вашим "Увы"!
Это очень полезная фича!
4 мар 14, 13:38    [15669410]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Exproment
Member

Откуда:
Сообщений: 416
iap
ZOOKABAKODER,

и я совершенно не согласен с Вашим "Увы"!
Это очень полезная фича!

iap, можете показать пару примеров полезности ? :)
4 мар 14, 13:42    [15669435]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Exproment
iap
ZOOKABAKODER,

и я совершенно не согласен с Вашим "Увы"!
Это очень полезная фича!

iap, можете показать пару примеров полезности ? :)
SELECT f1,f2,f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(f1),(f2),(f3))T(f))
FROM T;
SELECT *
FROM T
WHERE EXISTS(SELECT f1, f2, f3 INTERSECT 0,'20140304',NULL));
SELECT *
FROM deleted d JOIN inserted i ON d.ID=d.ID
WHERE EXISTS(SELECT d.* INTERSECT SELECT i.*);
Тут везде в подзапросах ссылка на значения полей текущей записи внешнего запроса.
4 мар 14, 13:59    [15669571]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
Во втором примере пропустил "SELECT" в INTERSECTе
4 мар 14, 14:00    [15669578]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
1. Может фича и баян, но, как видите, не все её знают. Или не все знают где она работает (в моём случае именно так).
2. IMHO это фича SQL, ну на крайний случай, это со времён царя гороха фича и по сею пору работает.
3. Ах эти SQLрушные срачи. :-)
4 мар 14, 14:08    [15669636]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
iap
ZOOKABAKODER,
и я совершенно не согласен с Вашим "Увы"!
Это очень полезная фича!

Где в фразе "Увы это не баг." вы увидели смысл что это "ВРЕДНАЯ/ЗЛАЯ/ПЛОХАЯ" фича?
4 мар 14, 14:12    [15669667]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
2. IMHO это фича SQL, ну на крайний случай, это со времён царя гороха фича и по сею пору работает

Фича то, что в подзапросе доступны поля внешнего запроса ?
Или что поля внешнего запроса не нужно сопровождать именем внешней таблицы ?
4 мар 14, 14:12    [15669672]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Glory
Фича то, что в подзапросе доступны поля внешнего запроса ?
Или что поля внешнего запроса не нужно сопровождать именем внешней таблицы ?

Не... Это я к тому что версия не нужна. Хотя, конечно, стоило указать, что-то типа "это в SQL с 8 по 11 есть".

И к слову:
iap
ZOOKABAKODER,
Это очень полезная фича!

Это очень вредная фича, т.к. усложняет чтение кода, и приводит к сложноуловимым ошибкам.
4 мар 14, 14:20    [15669735]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
Это очень вредная фича, т.к. усложняет чтение кода, и приводит к сложноуловимым ошибкам.

По документированному синтаксису select полное имя столбца нужно только для предотвращения коллизий одинаковых имен столбцов.
Во всех остальных случаях полное имя столбца необязательно.
4 мар 14, 14:23    [15669765]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
invm
Member

Откуда: Москва
Сообщений: 9825
ZOOKABAKODER
Это очень вредная фича, т.к. усложняет чтение кода, и приводит к сложноуловимым ошибкам.
Любую фичу можно использовать так, что это приведет к сложноуловимым ошибкам. Все дело в квалификации пользующего.
4 мар 14, 14:25    [15669779]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Вот пример с таблицами. Тот же эффект.
CREATE TABLE foo (f1 INT NOT NULL);
CREATE TABLE bar (f1 INT NOT NULL);
GO
INSERT INTO bar (f1)
VALUES	(1),(2);

INSERT INTO foo (f1)
VALUES	(1);
GO
CREATE VIEW bar42
AS
SELECT	f1
FROM	bar 
WHERE	f1 IN (SELECT f1 FROM foo);
GO
SELECT * FROM bar42;
GO
EXECUTE sys.sp_rename N'dbo.foo.f1', N'b1', 'COLUMN' ;
GO
SELECT * FROM bar42;
GO
DROP VIEW bar42;
DROP TABLE foo ;
DROP TABLE bar ;


Glory
ZOOKABAKODER
Это очень вредная фича, т.к. усложняет чтение кода, и приводит к сложноуловимым ошибкам.

По документированному синтаксису select полное имя столбца нужно только для предотвращения коллизий одинаковых имен столбцов.
Во всех остальных случаях полное имя столбца необязательно.

Ну мы тут не просинтаксис говорим. Но всёравно спасибо за инфу.

invm
ZOOKABAKODER
Это очень вредная фича, т.к. усложняет чтение кода, и приводит к сложноуловимым ошибкам.
Любую фичу можно использовать так, что это приведет к сложноуловимым ошибкам. Все дело в квалификации пользующего.

100% согласен. признаю, выпад мой был не в попад.

iap
SELECT f1,f2,f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(f1),(f2),(f3))T(f))
FROM T;
SELECT *
FROM T
WHERE EXISTS(SELECT f1, f2, f3 INTERSECT 0,'20140304',NULL));
SELECT *
FROM deleted d JOIN inserted i ON d.ID=d.ID
WHERE EXISTS(SELECT d.* INTERSECT SELECT i.*);
Тут везде в подзапросах ссылка на значения полей текущей записи внешнего запроса.

А что она даёт эта ссылка на внешнюю таблицу? Полные имена полей тоже работают, и так намного читабильнее IMHO.
CREATE TABLE bar (f1 INT NOT NULL, f2 INT NOT NULL, f3 INT NOT NULL);
GO
INSERT INTO bar (f1,f2, f3)
VALUES	(1,2,3);
GO
SELECT b.f1,b.f2,b.f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(b.f1),(b.f2),(b.f3))T(f))
FROM bar b;
GO
DROP TABLE bar ;
4 мар 14, 15:06    [15670147]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
iap
Member

Откуда: Москва
Сообщений: 47142
ZOOKABAKODER
Вот пример с таблицами. Тот же эффект.
CREATE TABLE foo (f1 INT NOT NULL);
CREATE TABLE bar (f1 INT NOT NULL);
GO
INSERT INTO bar (f1)
VALUES	(1),(2);

INSERT INTO foo (f1)
VALUES	(1);
GO
CREATE VIEW bar42
AS
SELECT	f1
FROM	bar 
WHERE	f1 IN (SELECT f1 FROM foo);
GO
SELECT * FROM bar42;
GO
EXECUTE sys.sp_rename N'dbo.foo.f1', N'b1', 'COLUMN' ;
GO
SELECT * FROM bar42;
GO
DROP VIEW bar42;
DROP TABLE foo ;
DROP TABLE bar ;



Glory
пропущено...

По документированному синтаксису select полное имя столбца нужно только для предотвращения коллизий одинаковых имен столбцов.
Во всех остальных случаях полное имя столбца необязательно.

Ну мы тут не просинтаксис говорим. Но всёравно спасибо за инфу.

invm
пропущено...
Любую фичу можно использовать так, что это приведет к сложноуловимым ошибкам. Все дело в квалификации пользующего.

100% согласен. признаю, выпад мой был не в попад.

iap
SELECT f1,f2,f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(f1),(f2),(f3))T(f))
FROM T;

SELECT *
FROM T
WHERE EXISTS(SELECT f1, f2, f3 INTERSECT 0,'20140304',NULL));

SELECT *
FROM deleted d JOIN inserted i ON d.ID=d.ID
WHERE EXISTS(SELECT d.* INTERSECT SELECT i.*);

Тут везде в подзапросах ссылка на значения полей текущей записи внешнего запроса.

А что она даёт эта ссылка на внешнюю таблицу? Полные имена полей тоже работают, и так намного читабильнее IMHO.
CREATE TABLE bar (f1 INT NOT NULL, f2 INT NOT NULL, f3 INT NOT NULL);
GO
INSERT INTO bar (f1,f2, f3)
VALUES	(1,2,3);
GO
SELECT b.f1,b.f2,b.f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(b.f1),(b.f2),(b.f3))T(f))
FROM bar b;
GO
DROP TABLE bar ;
Вы написали то же самое. Зачем?
Главное - мы избежали запроса из той же таблицы
с необходимостью привязки к внешнему запросу.
4 мар 14, 15:09    [15670179]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
Ну мы тут не просинтаксис говорим. Но всёравно спасибо за инфу.

А про что ? Требование к именованию объектов в запросе - это часть синтаксиса.
Или вы считаете, что для подзапросов должен быть свой особый синтаксис ?
4 мар 14, 15:12    [15670204]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Glory
ZOOKABAKODER
Ну мы тут не просинтаксис говорим. Но всёравно спасибо за инфу.

А про что ?

Сопровождение кода.

[quot Glory]
ZOOKABAKODER
Требование к именованию объектов в запросе - это часть синтаксиса.
Или вы считаете, что для подзапросов должен быть свой особый синтаксис ?

Ну это же софизм... Вы же не глупый человек... брррр...
4 мар 14, 15:17    [15670239]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
Ну это же софизм... Вы же не глупый человек... брррр...

Какой софизм
Вот вы пишите
select f1 from tab1 join tab2 on pk=fk
и считаете, что все нормально
а
select *, (select f1 from tab2) from tab1
почему то считаете ненормальным
Где логика ?
4 мар 14, 15:19    [15670266]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
iap
ZOOKABAKODER
Вот пример с таблицами. Тот же эффект.
А что она даёт эта ссылка на внешнюю таблицу? Полные имена полей тоже работают, и так намного читабильнее IMHO.
CREATE TABLE bar (f1 INT NOT NULL, f2 INT NOT NULL, f3 INT NOT NULL);
GO
INSERT INTO bar (f1,f2, f3)
VALUES	(1,2,3);
GO
SELECT b.f1,b.f2,b.f3,[f1+f2+f3]=(SELECT SUM(f) FROM(VALUES(b.f1),(b.f2),(b.f3))T(f))
FROM bar b;
GO
DROP TABLE bar ;
Вы написали то же самое. Зачем?
Главное - мы избежали запроса из той же таблицы
с необходимостью привязки к внешнему запросу.

Я написал без использования фичи которую мы тут обсуждаем. Я написал с полными именами полей. Читайте внимательнее.
4 мар 14, 15:21    [15670290]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Glory
Какой софизм

"Я обязательно использую в выражениях полное имя поля. ...чего и вам советую" И "Требование к именованию объектов в запросе - это часть синтаксиса." -> "мы говорим о синтаксисе"
Силлогизм неверен.

Glory
Вот вы пишите
select f1 from tab1 join tab2 on pk=fk
и считаете, что все нормально
а
select *, (select f1 from tab2) from tab1
почему то считаете ненормальным
Где логика ?

{Ctrl+F} по слову "join", не указывает на мои сообщения. Вы со мной разговариваете? ;-)
4 мар 14, 15:31    [15670398]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
Вы со мной разговариваете

Я с вами. А вы кажется сами с собой.

Я вас спрашиваю, в чем должна быть разница в синтаксисе двух приведенных запросов
Почему по-вашему мнению к полю f1 во 2ом запросе нельзя обращаться так, как в 1ом запросе ?
4 мар 14, 15:35    [15670460]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
ZOOKABAKODER
Member

Откуда:
Сообщений: 178
Glory
ZOOKABAKODER
Вы со мной разговариваете

Я с вами. А вы кажется сами с собой.

О! Вы на личности перешли... Вы наверное менеджер? :)

Glory
Я вас спрашиваю, в чем должна быть разница в синтаксисе двух приведенных запросов
Почему по-вашему мнению к полю f1 во 2ом запросе нельзя обращаться так, как в 1ом запросе ?

Если в tab1 и tab2 есть поле f1, вы имеете ввиду?
В разрезе требований синтаксиса: в "select f1 from tab1 join tab2 on pk=fk;" требуется полные имена писать, а в "select *, (select f1 from tab2) from tab1" -- не требуется. Но мы с вами, точнее я и воздух собравшийся около вашей головы, разговариваем про требования к коду в разрезе сопровождения проектов.
4 мар 14, 15:56    [15670669]     Ответить | Цитировать Сообщить модератору
 Re: Про лжебаг SQL.  [new]
Glory
Member

Откуда:
Сообщений: 104751
ZOOKABAKODER
В разрезе требований синтаксиса: в "select f1 from tab1 join tab2 on pk=fk;" требуется полные имена писать

НЕ требуется, если имена уникальны
4 мар 14, 15:58    [15670688]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить