MySQL, Boolean и Union

S_Gur
Дата: 23.09.2019 07:11:22
Всем доброго времени суток. Наткнулся давеча на интересную ситуацию. У меня есть несколько таблиц почти одинаковой структуры. В каждой из них есть одно и то же поле типа Boolean. Соответственно, в Дельфях я обрабатываю это поле как AsBoolean и до недавнего времени проблем не испытывал. До тех пор, пока мне не понадобилось написать представление, где идет выборка однотипных полей из трех таблиц, соединенных Union. Как только я попытался обработать это представление в Дельфях, мне тут же вылезла ошибка, что Дельфи не могут обработать это поле как Boolean. Пришлось работать с ним как AsInteger, сравнивая с 0 или 1. Эксперименты показали, что если во вьюхе закомментировать две любых таблицы и оставить выборку только из одной, проблема пропадает. Отсюда вопрос - за неимением в MySQL конструкции Cast [поле] As Boolean можно ли как-то скорректировать эту выборку? Я, конечно, могу выкрутиться, но в нескольких местах программы мне было бы очень удобно использовать это поле как булевское. Есть какие-нибудь идеи?
DimaBr
Дата: 23.09.2019 07:49:27
Cast [поле] As bit
S_Gur
Дата: 23.09.2019 07:52:27
Разве Дельфи считает MySQL-вский Bit булевским полем? Вроде бы для MySQL Boolean - это TinyInt(1)? Но я попробую, спасибо
S_Gur
Дата: 23.09.2019 08:12:54
Bit не катит однозначно. Он не воспринимается дельфями как Boolean, даже в гридах по умолчанию вместо галочки просто 0 или 1 рисуется. И AsBoolean, соответственно, не работает
s62
Дата: 23.09.2019 09:56:48
S_Gur,
наверное всё это зависит от того, какими компонентами доступа к БД вы пользуетесь. Вы какими пользуетесь?
S_Gur
Дата: 23.09.2019 13:08:40
UniDAC-овскими. И - нет, это не зависит от компонент. Эксперименты показали, что при селекте из одной таблицы поле в датасете получает тип ftBoolean, а при селекте с юнионами - ftLargeInt. Это приколы MySQL
DimaBr
Дата: 23.09.2019 14:03:52
S_Gur
UniDAC-овскими. И - нет, это не зависит от компонент. Эксперименты показали, что при селекте из одной таблицы поле в датасете получает тип ftBoolean, а при селекте с юнионами - ftLargeInt. Это приколы MySQL

Первый SELECT в UNION определяет имена и типы полей
_Vasilisk_
Дата: 23.09.2019 14:11:43
S_Gur
Это приколы MySQ
В MySQL нет типа BOOLEAN. Вообще. А то, что есть - это алиас для типа TINYINT(1). Т.е. однобайтовое число из одной цифры.

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

Правило преобразования типов у MySQL простые
https://dev.mysql.com/doc/refman/8.0/en/union.html
If the data types of corresponding SELECT columns do not match, the types and lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements.
(если типы выбираемых колонок не соответствует друг-другу, то результирующая колонка получает общий тип)

Отсюда вывод - либо вы объединяете разные типы полей, либо дак не может поднять типы полей из сложного селекта
kill_zdm
Дата: 23.09.2019 14:14:55
а fieldbyname('').Value, т.е. без явного приведения к типу - то же падает? Порой выручало, в юнидаках именно, но порой и наоборот усугубляло.


Понимаю, что не совсем по делу, по сколько Вы сказали, что было бы удобно использовать - но я фактически отказался от boolean из за таких вот приколов, то компонент, то СУБД... То дэвекспресс в неадеквате, то вьюшка , то приведение к типу... smallint фарева )))
S_Gur
Дата: 23.09.2019 17:54:18
_Vasilisk_
S_Gur
Это приколы MySQ
В MySQL нет типа BOOLEAN. Вообще. А то, что есть - это алиас для типа TINYINT(1). Т.е. однобайтовое число из одной цифры.

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

Правило преобразования типов у MySQL простые
https://dev.mysql.com/doc/refman/8.0/en/union.html
If the data types of corresponding SELECT columns do not match, the types and lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements.
(если типы выбираемых колонок не соответствует друг-другу, то результирующая колонка получает общий тип)

Отсюда вывод - либо вы объединяете разные типы полей, либо дак не может поднять типы полей из сложного селекта


Очень хороший вывод. Жаль, что скороспелый и неверный

Таблица 1:

Create Table If Not Exists `tbVoucherTypeVPNServiceLinks`
(`biID` BigInt UnSigned Not Null Primary Key Auto_Increment Comment 'Уникальный идентификатор',
`biVoucherTypeID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор типа ваучера',
`biVPNServiceID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор услуги VPN',
`vcRemark` VarChar(2000) Default '…' Not Null Comment 'Комментарий',
`bIsDeletable` Boolean Default 0 Not Null Comment 'Признак запрещения удаления записи',
Foreign Key (`biVoucherTypeID`) References `tbVoucherTypes` (`biID`),
Foreign Key (`biVPNServiceID`) References `tbVPNServices` (`biID`))
ENGINE=InnoDB Default CharSet=utf8 Auto_Increment=0 Encryption = 'Y' Comment='Список связок типов ваучеров с услугами VPN';

Таблица 2:

Create Table If Not Exists `tbVoucherTypeEMailServiceLinks`
(`biID` BigInt UnSigned Not Null Primary Key Auto_Increment Comment 'Уникальный идентификатор',
`biVoucherTypeID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор типа ваучера',
`biEMailServiceID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор услуги VPN',
`vcRemark` VarChar(2000) Default '…' Not Null Comment 'Комментарий',
`bIsDeletable` Boolean Default 0 Not Null Comment 'Признак запрещения удаления записи',
Foreign Key (`biVoucherTypeID`) References `tbVoucherTypes` (`biID`),
Foreign Key (`biEMailServiceID`) References `tbEMailServices` (`biID`))
ENGINE=InnoDB Default CharSet=utf8 Auto_Increment=0 Encryption = 'Y' Comment='Список связок типов ваучеров с услугами электронной почты';

Таблица 3:

Create Table If Not Exists `tbVoucherTypeFSServiceLinks`
(`biID` BigInt UnSigned Not Null Primary Key Auto_Increment Comment 'Уникальный идентификатор',
`biVoucherTypeID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор типа ваучера',
`biFSServiceID` BigInt UnSigned Default 0 Not Null Comment 'Идентификатор услуги VPN',
`vcRemark` VarChar(2000) Default '…' Not Null Comment 'Комментарий',
`bIsDeletable` Boolean Default 0 Not Null Comment 'Признак запрещения удаления записи',
Foreign Key (`biVoucherTypeID`) References `tbVoucherTypes` (`biID`),
Foreign Key (`biFSServiceID`) References `tbFSServices` (`biID`))
ENGINE=InnoDB Default CharSet=utf8 Auto_Increment=0 Encryption = 'Y' Comment='Список связок типов ваучеров с услугами файлового хранилища';

Представление:

Create Or Replace View `vwVoucherTypeServiceLinks`

As
Select
A.`biID`,
0 As tiServiceType,
A.`biVoucherTypeID`,
A.`biVPNServiceID` As biServiceID,
A.`vcRemark`,
A.`bIsDeletable`,
B.`vcName` As vcVoucherTypeName,
C.`vcName` As vcServiceName
From
`tbVoucherTypeVPNServiceLinks` A,
`tbVoucherTypes` B,
`tbVPNServices` C
Where
A.`biID` > 0
And B.`biID` = A.`biVoucherTypeID`
And C.`biID` = A.`biVPNServiceID`
Union All
Select
A.`biID`,
1 As tiServiceType,
A.`biVoucherTypeID`,
A.`biEMailServiceID` As `biServiceID`,
A.`vcRemark`,
A.`bIsDeletable`,
B.`vcName` As vcVoucherTypeName,
C.`vcName` As vcServiceName
From
`tbVoucherTypeEMailServiceLinks` A,
`tbVoucherTypes` B,
`tbEMailServices` C
Where
A.`biID` > 0
And B.`biID` = A.`biVoucherTypeID`
And C.`biID` = A.`biEMailServiceID`
Union All
Select
A.`biID`,
2 As tiServiceType,
A.`biVoucherTypeID`,
A.`biFSServiceID` As `biServiceID`,
A.`vcRemark`,
A.`bIsDeletable`,
B.`vcName` As vcVoucherTypeName,
C.`vcName` As vcServiceName
From
`tbVoucherTypeFSServiceLinks` A,
`tbVoucherTypes` B,
`tbFSServices` C
Where
A.`biID` > 0
And B.`biID` = A.`biVoucherTypeID`
And C.`biID` = A.`biFSServiceID`;

Программа валится на поле`bIsDeletable`. И какой из ваших "либо" тут мог сработать? Сложный селект "Select * From `vwVoucherTypeServiceLinks`" или разные типы полей?