정수를 천정으로 캐스팅하는 데 문제가 있음 (10 진수)


10

이 시나리오가 있습니다 .MySQL이 가장 큰 십진수 값을 가져 와서 다른 값을 캐스트하려고합니다.

문제는이 쿼리가 외부 라이브러리에 의해 생성되므로 적어도이 수준에서는이 코드를 제어 할 수 없다는 것입니다. 이 문제를 해결하는 방법에 대한 아이디어가 있습니까?

SELECT 20 AS x
  UNION SELECT null
  UNION SELECT 2.2;
+------+
| x    |
+------+
|  9.9 | -- why from 20 to 9.9
| NULL |
|  2.2 |
+------+

예상 결과

+------+
| x    |
+------+
|   20 | -- or 20.0, doesn't matter really in my case
| NULL |
|  2.2 |
+------+

더 많은 컨텍스트를 추가하고 확장 라이브러리 http://entityframework-extensions.net/ 과 함께 Entity Framework 6을 사용하여 일괄 변경 사항, 특히 context.BulkSaveChanges () 메서드를 변경 사항으로 저장합니다.이 라이브러리는 "select union" .


1
어떻게 든 20이 9.9가됩니까?! 옳지 않은 것 같습니다.
dbdemon

2
DBFiddle의 MySQL 8.0은 넌센스를 보여줍니다 : dbfiddle.uk/…
dezso

더 혼란스러운 ... SELECT 20 UNION SELECT null UNION SELECT 40 UNION SELECT 4.3;잘 작동합니다
Evan Carroll

Pls는 필요한 출력을 게시합니다. 또한 생성되는 코드를 얼마나 많이 제어 할 수 있습니까? 예를 들어 유형을 20에서 20.0으로 변경하거나 2.2에서 2로 유형을 변경할 수 있습니까?
Qsigma

이제 더 많은 컨텍스트를 추가했습니다. 제 경우 가능한 한 가지 해결책은 코드에서 값을 20.0으로 강제하는 것입니다. 문제를 테스트하고 수정했지만 null이 관련된 특정 시나리오에서만 발생하기 때문에 버그처럼 보입니다. 그 순서.
ngcbassman

답변:


9

나에게 버그처럼 보이며이 수수께끼 같은 행동을 확인할 수 있습니다.

10.2.14-MariaDB

가능하면 정수 값을 두 배로 캐스트 할 수 있습니다.

SELECT cast(20 as double) UNION SELECT null UNION SELECT 2.2;

또는 이중 값이 먼저 있는지 확인하십시오.

SELECT 2.2 UNION SELECT null UNION SELECT 22;

@Evan Carroll의 답변에서 주석을 읽은 후 추가 관찰

select 20 union select null union select 2;
+------+
| 20   |
+------+
|   20 |
| NULL |
|    2 |
+------+

좋아, int 값을 사용하면 오류가 발생하지 않는 것 같습니다.

select 20 union select null union select 9.0;
+------+
| 20   |
+------+
| 9.9  |
| NULL |
| 9.0  |
+------+

오류 : 출력이 10 진수 (2,1) 인 것 같습니다

create table tmp as select * from (select 20 as x 
                                   union 
                                   select null 
                                   union 
                                   select 9.0) as t

describe tmp;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| x     | decimal(2,1) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+

오류는 명령 행 인터페이스와 분리되지 않으며 python2-mysql-1.3.12-1.fc27.x86_64에도 존재합니다.

>>> import MySQLdb
>>> db = MySQLdb.connect(host="localhost", user="*****", passwd="*****", db="test") 
>>> cur = db.cursor()
>>> cur.execute("SELECT 20 union select null union select 2.2")
3L
>>> for row in cur.fetchall() :
...     print row
... 
(Decimal('9.9'),)
(None,)
(Decimal('2.2'),)

이상하게도 null이 처음 또는 마지막으로 이동하면 오류가 사라집니다.

select null union select 20 union select 9.0;
select 20 union select 9.0 union select null;

+------+
| NULL |
+------+
| NULL |
| 20.0 |
| 9.0  |
+------+

널이 먼저 배치되면 결과 유형은 decimal (20,1)입니다. 널이 마지막으로 배치되면 결과 유형은 decimal (3,1)입니다

다른 레그가 유니온에 추가되면 오류가 사라집니다.

select 20 union select 6 union select null union select 9.0;
+------+
| 20   |
+------+
| 20.0 |
| 6.0  |
| NULL |
| 9.0  |
+------+

결과 유형 10 진수 (20,1)

중간에 다른 null을 추가하면 오류가 유지됩니다.

select 20 union select null union select null union select 9.0;
+------+
| 20   |
+------+
| 9.9  |
| NULL |
| 9.0  |
+------+

그러나 처음에 null을 추가하면 문제가 해결됩니다.

select null union select 20 union select null union select null union select 9.0;
+------+
| NULL |
+------+
| NULL |
| 20.0 |
| 9.0  |
+------+

예상대로 첫 번째 값을 decimal (3,1)로 캐스팅하면 작동합니다.

마지막으로 decimal (2,1)로 명시 적으로 캐스팅하면 동일한 오류가 발생하지만 경고가 표시됩니다.

select cast(20 as decimal(2,1));
+--------------------------+
| cast(20 as decimal(2,1)) |
+--------------------------+
| 9.9                      |
+--------------------------+
1 row in set, 1 warning (0.00 sec)

1
CAST to DOUBLE은 MySQL의 구문 오류입니다. 소수는 대신 작동합니다.SELECT CAST(20 AS DECIMAL) AS x UNION SELECT NULL UNION SELECT 2.2;
Qsigma

4
나는 이것을 MariaDB Jira에서 버그로보고 할 자유를 얻었다
dbdemon

1
이 문제는 MariaDB 10.3에서 수정 된 것으로 보입니다. (방금 10.3.6으로 테스트했으며 10.3.1도 작동합니다.)
dbdemon

2
흥미롭게도 20as 를 지정하면 문제가 없습니다 020. 동작은 MariaDB 10.2MySQL 8.0에서 동일 합니다. 리터럴 의 길이가 결합 된 열의 유형에 영향을 미치는 것처럼 보입니다 . 어쨌든 이것은 분명히 내 책의 버그입니다.
Andriy M

1
null이 없어도 MySQL 8.0에서 문제가 발생 합니다 (MariaDB 10.2에서는 정상적으로 작동하지만). 선행 0 또는 계산을 포함하면 열 크기에도 차이가 있습니다.
Mick O'Hea

5

버그 MDEV-15999

dbdemon이 제출 한 버그 MDEV-15999 가이를 보고했습니다. 10.3.1에서 수정되었습니다.

이상한 MySQL / MariaDB 성격

문서에서

첫 번째 SELECT명령문의 열 이름은 리턴 된 결과의 열 이름으로 사용됩니다. SELECT문의 해당 위치에 나열된 선택된 열 은 동일한 데이터 유형을 가져야합니다. 예를 들어 첫 번째 문에서 선택한 첫 번째 열은 다른 문에서 선택한 첫 번째 열과 동일한 유형이어야합니다.

해당 SELECT컬럼 의 데이터 유형이 일치 하지 않으면 UNION결과 의 컬럼 유형 및 길이는 모든 SELECT명령문에서 검색 한 값을 고려합니다 .

이 경우, 그들은 화해 decimalintegerA를 정수를 홍보하여 decimal그것을 포함 할 수 없습니다. 나는 그것이 끔찍하다는 것을 알고 있지만 똑같이 끔찍한 것은 이와 같이 조용히 행동하는 것입니다.

SELECT CAST(20 AS decimal(2,1));
+--------------------------+
| CAST(20 AS decimal(2,1)) |
+--------------------------+
|                      9.9 |
+--------------------------+

이 문제에 대한 길을 열어주는 것 같습니다.


SELECT cast(20 as signed) UNION SELECT null UNION SELECT 2.2 ;동일한 (9.9) 잘못된 결과를 생성합니다. 그러나 "unsgned"를 사용하면 모든 것이 잘됩니다. 이동 그림 ...
ypercubeᵀᴹ

SELECT -20 UNION SELECT null UNION SELECT 2.2 ;마찬가지로, 너무 제대로 작동SELECT 20. UNION SELECT null UNION SELECT 2.2 ;
안드리 M

3
여기서 중요한 통찰력은 MySQL이 보유 할 수있는 데이터 형식을 선택한 것입니다 2.2있지만 너무 좁은 보류로를 20. 마지막 select 절을 으로 변경 하면 첫 번째 행 (암시 적으로 실행 ) CAST(2.2 AS DECIMAL(10,2))을 제공 하여이를 확인할 수 있습니다 . 20.0CAST(20 AS DECIMAL(10,2))
IMSoP

1
이상한 점은 데이터 유형을 기반으로하는 것이 아닙니다 2.2. 당신이 시도 select 20000 union select null union select 2.22하면 9999.99,에서 decimal(6,2). 값을 보유하기에는 항상 한 자리가 너무 짧습니다.
Mick O'Hea

1
@Mick 예. 당신이 던져 경우 NULL중간 값은 정밀도 1 단을 계산합니다.
살만 A
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.