使用ADO读出的BIGINT字段类型,形成的VARIANT是VT_DECIMAL类型

本文总结了使用M$SQL过程中遇到的问题,包括ADO读取BIGINT字段类型的问题、SQL查询分析器的使用误区以及存储过程调用的复杂性。提供了一种通过ODBC API直接调用存储过程的方法。

平民程序 - linghuye's blog

天下风云出我辈,一入江湖岁月催。皇图霸业谈笑中,不胜人生一场醉。提剑跨骑挥鬼雨,白骨如山鸟惊飞。尘事如潮人如水,只笑江湖几人回。

随笔 - 203, 文章 - 0, 评论 - 516, 引用 - 0

导航

公告

愿绵泊的悲哀浸透我颓废的一生

围在城里的人想逃出来,城外的人想冲进去,对婚姻也罢,职业也罢,人生的愿望大多如此.

常用链接

留言簿(106)

随笔分类

随笔档案

收藏夹

友情链接

目前常用链接

<script language="javascript"> function searchgoogle(key,evt,site) { if(evt.keycode==13 || evt.keycode==0 || evt.type =='click') { key.focus(); var keystr = encodeuricomponent(key.value); url = "http://www.google.com/search?q="; url = url+keystr; url += "&ie=utf-8&oe=gb2312&hl=zh-cn&domains="+site+"&sitesearch="+site; window.location=url; return false; } } </script>

搜索

  •  

最新评论

阅读排行榜

评论排行榜

M$ SQL的问题

最近用M$ SQL的遇到些问题,总结一下.

1. 使用ADO读出的BIGINT字段类型,形成的VARIANT是VT_DECIMAL类型,而非想象中的VT_I8.更要命的是 VariantChangeType在Win2000下转换VT_DECIMAL->VT_I8或反之,都出错,该API返回错误的数据类型,而 WinXP和Win2003下不会.结论是Win2000内核对VT_I8支持有误,当前SP4仍为解决该问题.Bae, Hyun-jik给出一个hack绕过该问题. Refer to:
http://groups.google.com/group/microsoft.public.data.oledb/browse_thread/thread/3ba6ff6e76186d95/c89a98d77a8fdb52?lnk=st&q=vt_decimal+to+vt_i8&rnum=1&hl=zh-CN#c89a98d77a8fdb52
http://groups.google.com/group/microsoft.public.win32.programmer.ole/browse_thread/thread/ee793c37192460d8/3f3ca1b412620ac6?lnk=st&q=vt_decimal+to+vt_i8&rnum=2&hl=zh-CN#3f3ca1b412620ac6

2.不能在SQL查询分析器下,选择文本的状态下,然后F5执行查询,执行的是选择文本.偶不知道,检查了4个小时的语法后发现的.

3.ADO的Command对象带参数存储过程调用方式真低能,一个一个Parameter对象地创建,设置,赋值,这样的方式写出的都是垃圾代码.
改 用adCmdText方式直接进行SQL语法调用EXECUTE procname @varInput,却无法从ADO的Command对象中取得返回值,于是被逼使用SELECT ErrCode = 1记录集返回.这样,对于复杂的存储过程中间多次进行出错返回的,出现多个SELECT语句,此时ADO将返回的一个多数据集对象,其中只有一个为打开, 其他均为关闭,(奇怪的逻辑),于是有如下丑陋的代码:
int ExecuteStoreProcedure(const char* szSQL)
{
 try
 { 
  _variant_t vRecords;
  _RecordsetPtr ptrRcs = m_ptrConnection->Execute(_bstr_t(szSQL), &vRecords, adOptionUnspecified);
  while(ptrRcs != NULL)
  { 
   if(ptrRcs->GetState() == adStateOpen)
   {
    return ptrRcs->GetFields()->GetItem("ErrCode")->GetValue();
   }
   ptrRcs = ptrRcs->NextRecordset(&vRecords);
  }
  return ERROR_UNKNOWN;
 }
 catch(_com_error& e)
 { 
  _bstr_t bstrErrMsg = e.Description();
  DUMP_COM_ERROR(e);
  return ERROR_UNKNOWN;
 }
 catch(...)
 {
  return ERROR_UNKNOWN;
 }
}

只是不知有没更简单的方法取回存储过程的return值,在使用直接SQL执行调用的方式下!
推荐大家使用MYSQL.

posted on 2006-06-29 17:29 linghuye 阅读(379) 评论(2)  编辑 收藏 引用 所属分类: 编程札记

评论

# re: M$ SQL的问题  回复  更多评论   

ADO的效率确实是不敢恭维。不过还在还有ODBC SQL API直接获取存储过程的方法。不用写ADO比较蹩脚的代码。(据说DB Lib是专门针对MSSQL优化的,实际测试一点都没有看出来,还是ODBC API速度比较稳定。)
以前写了一个,速度比AD快很多,主要是没有那些乱七八糟的属性,直来直去比较方便省事。博得楼主一笑。

void ODBCBase::ExecuteProc(char * szProcName,vector<string> vectorParam,int iPamaCount,int iReCordCount, int * iResult, int * iRowCount,vector<RecordSetCell> * recordset)
{
SQLVARCHAR SqlPama[MAXPAMACOUNT][MAXPAMASIZE] = {'/0'}; //´´½¨Ò»¸ö¶þάÊý×éÀ´½ÓÊÕÊý¾Ý
SQLCHAR SqlColValue[MAXPAMACOUNT][MAXPAMASIZE]; //¶¨Òå½á¹û¼¯µÄ°ï¶¨ÁÐ
SQLINTEGER CountInd = 0;
int i;
char szLog[MAXCHARBUFF];
RecordSetCell cell;

*iRowCount = 0;

for(i = 0; i < vectorParam.size(); i++)
{
CopyMemory(SqlPama[i], vectorParam[i].c_str(), vectorParam[i].length());
}
CopyMemory(SqlPama[i], &CountInd, sizeof(BYTE)*2);

Retcode = SQLAllocHandle(SQL_HANDLE_STMT, Hdbc,&Hstmt);
if(SQL_SUCCESS != Retcode && SQL_SUCCESS_WITH_INFO != Retcode)
{
printf("/nSQL Set STMT Error.");
return;
}

if(Hstmt != NULL)
{
//°ó¶¨²ÎÊý
for(i=1 ;i<= iPamaCount; i++)
{
if(i == iPamaCount)
{
Retcode = SQLBindParameter(Hstmt, i, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 2, 0, SqlPama[i - 1], 2, 0);
if(Retcode != SQL_SUCCESS && Retcode != SQL_SUCCESS_WITH_INFO)
{
printf("/nProc PARAM Error.");
return;
}
}
else
{
Retcode = SQLBindParameter(Hstmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, MAXPAMASIZE, 0, SqlPama[i - 1], MAXPAMASIZE, 0);
if(Retcode != SQL_SUCCESS && Retcode != SQL_SUCCESS_WITH_INFO)
{
printf("/nProc PARAM Error.");
return;
}
}
}

Retcode = SQLExecDirect(Hstmt, (SQLCHAR *)szProcName, SQL_NTS);
if(SQL_SUCCESS != Retcode && SQL_SUCCESS_WITH_INFO != Retcode)
{
SQLCHAR ConnStrOut[MAXBUFLEN];
SQLCHAR szErrorMsg[MAXBUFLEN];
SQLSMALLINT cbConnStrOut = 0;
SQLINTEGER nErrorCode = 0;
SQLSMALLINT nLenErrorMsg = 0;

Retcode = SQLGetDiagRec(SQL_HANDLE_STMT,
Hstmt,
1,
ConnStrOut,
&nErrorCode,
szErrorMsg,
MAXBUFLEN,
&nLenErrorMsg);

printf("%s/n", szErrorMsg);
sysLog->LogText((char *)szErrorMsg);
return;
}
else
{
printf("·µ»ØÖµ: %s/n", SqlPama[iPamaCount - 1]);
sprintf(szLog, "·µ»ØÖµ: %s", SqlPama[iPamaCount - 1]);
sysLog->LogText((char *)szLog);

//°ó¶¨ÁÐÃû
for(i = 1; i <= iReCordCount; i++)
{
SQLBindCol(Hstmt, i, SQL_C_CHAR, &SqlColValue[i-1], MAXBUFLEN, &CountInd);
}

*iResult = atoi((char *)SqlPama[iPamaCount - 1]);

//µÃµ½½á¹û¼¯
while(1)
{
Retcode = SQLFetch(Hstmt);
if(Retcode == SQL_SUCCESS || Retcode == SQL_SUCCESS_WITH_INFO)
{
for(i = 1;i <= iReCordCount; i++)
{
SQLGetData(Hstmt, i, SQL_VARCHAR, &SqlColValue[i-1], MAXBUFLEN, &CountInd);
//printf(", %s",SqlColValue[i-1]);
//½«Êý¾Ý¸´ÖƵ½Ò»¸ö½á¹¹ÖÐ,È»ºó°ÑÕâ¸ö½á¹¹´«Èëvector
cell.iCol = i;
cell.iRow = *iRowCount;
cell.strCellText = string((char *)SqlColValue[i-1]);

recordset->push_back(cell);
}
//printf("/n");
*iRowCount = *iRowCount + 1;
}
else
{
SQLCHAR ConnStrOut[MAXBUFLEN] = {'/0'};
SQLCHAR szErrorMsg[MAXBUFLEN] = {'/0'};
SQLSMALLINT cbConnStrOut = 0;
SQLINTEGER nErrorCode = 0;
SQLSMALLINT nLenErrorMsg = 0;

Retcode = SQLGetDiagRec(SQL_HANDLE_STMT,
Hstmt,
1,
ConnStrOut,
&nErrorCode,
szErrorMsg,
MAXBUFLEN,
&nLenErrorMsg);

printf("%s/n", szErrorMsg);
break;
}
}
}
}
2006-06-30 11:25 | freeeyes

# re: M$ SQL的问题  回复  更多评论   


Retcode = SQLFreeHandle(SQL_HANDLE_STMT, Hstmt);
if(Retcode != SQL_SUCCESS && Retcode != SQL_SUCCESS_WITH_INFO)
{
printf("Free Hstmt Error");
}

}
2006-06-30 11:28 | freeeyes


标题
姓名
主页
验证码*
内容(提交失败后,可以通过“恢复上次提交”恢复刚刚提交的内容)

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
[使用Ctrl+Enter键可以直接提交]
 
相关链接:


marginheight="0" marginwidth="0" src="http://www.cnitblog.com/ad.htm" style="border: 0px solid rgb(102, 102, 102);" allowtransparency="true" frameborder="0" height="60" scrolling="no" width="468">
51YES网站统计系统 marginwidth="0" marginheight="0" hspace="0" vspace="0" src="http://count4.51yes.com/sa.aspx?id=45505990&refe=&location=http%3A//www.cnitblog.com/linghuye/archive/2006/06/29/13070.html&color=32x&resolution=1600x900&returning=0&language=undefined&ua=Mozilla/5.0%20%28Windows%3B%20U%3B%20Windows%20NT%205.1%3B%20zh-CN%3B%20rv%3A1.8.1.17%29%20Gecko/20080829%20Firefox/2.0.0.17" frameborder="0" height="0" scrolling="no" width="0">
<think>我们查询的目标是获取decimalbigint类型字段的长度信息。在MySQL中,字段的长度信息可以通过`information_schema.COLUMNS`表来获取。具体来说: - `NUMERIC_PRECISION` 列表示数字类型的精度(总共的位数) - `NUMERIC_SCALE` 列表示数字类型的小数位数(仅对decimal类型有意义) - 对于整数类型(如bigint),我们通常关心的是它的显示宽度(如果有指定)或者它的字节长度(固定)。但注意,在`information_schema.COLUMNS`表中,整数类型(如bigint)的精度(`NUMERIC_PRECISION`)会表示该类型的最大位数,而小数位数(`NUMERIC_SCALE`)为0。 另外,引用[1]中提到INNODB_SYS_COLUMNS.len表示列字节长度,但注意这是InnoDB引擎内部系统表,通常我们使用标准的information_schema.COLUMNS表来获取信息,因为它具有更好的兼容性。 对于bigint类型,它的固定字节长度是8字节,所以它的最大位数(精度)是19(因为8字节可以存储从-2^63到2^63-1,即-9223372036854775808到9223372036854775807,共19位数字)。而decimal类型的长度由精度和小数位数共同决定。 因此,我们可以通过以下查询来获取decimalbigint类型字段的长度信息(这里长度指的是精度和标度,对于bigint,小数位数总是0): 查询语句如下: ```sql SELECT TABLE_SCHEMA AS '数据库名', TABLE_NAME AS '表名', COLUMN_NAME AS '字段名', DATA_TYPE AS '数据类型', IF(DATA_TYPE = 'decimal', CONCAT(NUMERIC_PRECISION, ',', NUMERIC_SCALE), IF(DATA_TYPE = 'bigint', CAST(NUMERIC_PRECISION AS CHAR), NULL)) AS '长度信息' -- 对于decimal返回"精度,标度",对于bigint返回精度(即最大位数) FROM information_schema.COLUMNS WHERE DATA_TYPE IN ('decimal', 'bigint') AND TABLE_SCHEMA = 'your_database_name'; -- 替换为你的数据库名 ``` 注意:上述查询中,我们只针对decimalbigint类型。对于decimal,我们将其精度和小数位数组合成字符串(如"10,2"表示精度10,小数位数2)。对于bigint,我们返回其精度(即19,因为bigint总是19位数字,除非是unsigned bigint,其精度为20位,但MySQLbigint类型的精度在information_schema中会正确表示)。 但是,需要注意的是,在MySQL中,bigint类型在`information_schema.COLUMNS`表中的`NUMERIC_PRECISION`列的值是固定的,有符号时为19,无符号时为20。decimal类型的精度和标度则根据定义而定。 另外,如果我们需要获取字节长度(如引用[1]中提到的INNODB_SYS_COLUMNS.len),我们可以根据数据类型进行转换: - bigint类型固定为8字节 - decimal类型存储空间计算较为复杂,它取决于精度。MySQLdecimal类型每9位数字使用4个字节,剩余的数字使用相应比例的字节数(例如,1-2位数字用1个字节,3-4位数字用2个字节,5-6位数字用3个字节,7-9位数字用4个字节)。但是,通常我们更关心的是精度和标度,而不是底层的存储字节数。 因此,如果用户需要的是存储的字节长度,我们可以通过计算得到,但这不是标准做法。通常,我们在设计表时更关心的是精度(总位数)和小数位数。 所以,根据问题,我们返回的是精度和标度(对于decimal)以及精度(对于bigint)作为长度信息。如果需要字节长度,可以额外计算。 但是,由于问题中要求的是“长度信息”,而长度信息在数据库中通常有两种含义:显示长度和存储长度。根据引用[1]中提到的“列字节长度”,如果用户需要的是存储字节长度,我们可以这样查询: 由于计算存储字节长度比较复杂,我们可以使用以下方法(但注意,这不是information_schema中直接提供的,需要根据规则计算): - 对于bigint:8字节 - 对于decimal:计算规则如下(根据MySQL官方文档): 每9位数字使用4字节,剩余的数字: 1-2位:1字节 3-4位:2字节 5-6位:3字节 7-9位:4字节 因此,总字节数 = (整数部分位数 + 小数部分位数) 按照上述规则计算。 但是,在information_schema中并没有直接提供存储字节长度,所以我们可以通过一个函数来计算,或者使用CASE表达式。不过,在查询中直接计算会使得SQL非常复杂。因此,我们通常只查询精度和标度。 因此,我建议分两种情况回答: 1. 如果用户需要的是精度和标度(即定义的长度),则使用上面的查询。 2. 如果用户需要的是存储的字节长度,则我们可以通过计算得到,但需要编写复杂的表达式。 考虑到问题中并没有明确是哪种长度,但根据引用[1]中提到的“列字节长度”,我们假设用户需要的是存储字节长度。那么我们可以这样查询: 注意:在information_schema.COLUMNS表中,decimal类型的精度和小数位数分别存储在`NUMERIC_PRECISION`和`NUMERIC_SCALE`中。我们可以根据这两个值计算存储字节长度。 计算decimal存储字节长度的公式: 设整数部分位数 = NUMERIC_PRECISION - NUMERIC_SCALE 总位数 = NUMERIC_PRECISION 然后,将总位数分成多个9位数字的组(每个组4字节),再加上剩余位数的字节数。 具体计算步骤: 1. 计算整数部分位数:int_part = NUMERIC_PRECISION - NUMERIC_SCALE 2. 计算小数部分位数:frac_part = NUMERIC_SCALE 3. 总位数 = NUMERIC_PRECISION 4. 总字节数 = (int_part DIV 9) * 4 + (frac_part DIV 9) * 4 + (根据余数计算:int_part % 9 和 frac_part % 9 分别对应余数部分,然后按照上述规则换算成字节数) 但是,实际上,decimal存储是按整体位数来计算的,而不是分开整数和小数。根据MySQL官方文档,存储要求如下: 存储每9位数字需要4个字节,剩下的位数所需的存储如下表: 剩余位数 字节数 0 0 1-2 1 3-4 2 5-6 3 7-9 4 因此,我们可以这样计算: 设 digits = NUMERIC_PRECISION bytes = (digits DIV 9) * 4 + CASE digits % 9 WHEN 0 THEN 0 WHEN 1 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 2 WHEN 5 THEN 3 WHEN 6 THEN 3 WHEN 7 THEN 4 WHEN 8 THEN 4 END 但是,注意:decimal存储字节数实际上是根据整数部分和小数部分分别计算?实际上,文档中说明的是根据总位数(精度)来划分的。然而,经过查阅官方文档,实际上decimal存储是分开整数部分和小数部分分别进行存储的,所以需要分别计算整数部分和小数部分的字节数,然后相加。 官方文档:https://dev.mysql.com/doc/refman/8.0/en/precision-math-decimal-characteristics.html 存储要求为每9位数字4个字节,剩余的位数需要额外的空间: 剩余0位:0字节 剩余1-2位:1字节 剩余3-4位:2字节 剩余5-6位:3字节 剩余7-9位:4字节 例如,DECIMAL(18,9) 在小数点两边各有9位数字,所以整数部分9位,小数部分9位。每部分4个字节,总共8字节。 而DECIMAL(20,6) 整数部分有14位,小数部分6位。 整数部分:14位 = 9+5,所以9位部分需要4字节,剩下的5位需要3字节,整数部分共7字节。 小数部分:6位 = 0+6,所以0个9位部分,剩下的6位需要3字节。 总共10字节。 因此,我们需要分别计算整数部分和小数部分: 整数部分位数 = NUMERIC_PRECISION - NUMERIC_SCALE 小数部分位数 = NUMERIC_SCALE 整数部分字节数 = (整数部分位数 DIV 9) * 4 + CASE 整数部分位数 % 9 WHEN 0 THEN 0 ELSE CASE 整数部分位数 % 9 WHEN 1 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 2 WHEN 5 THEN 3 WHEN 6 THEN 3 WHEN 7 THEN 4 WHEN 8 THEN 4 END END 小数部分字节数 = (小数部分位数 DIV 9) * 4 + CASE 小数部分位数 % 9 WHEN 0 THEN 0 ELSE CASE 小数部分位数 % 9 ... 同上 ... END END 总字节数 = 整数部分字节数 + 小数部分字节数 由于这个计算在SQL中写起来非常冗长,我们可以考虑使用存储过程或者用户自定义函数。但是,在查询中直接使用CASE表达式也是可行的,只是SQL较长。 因此,如果用户需要存储字节长度,我们可以构造如下查询: ```sql SELECT TABLE_SCHEMA AS '数据库名', TABLE_NAME AS '表名', COLUMN_NAME AS '字段名', DATA_TYPE AS '数据类型', -- 对于bigint,直接返回8 -- 对于decimal,计算存储字节数 IF(DATA_TYPE = 'bigint', 8, IF(DATA_TYPE = 'decimal', (FLOOR((NUMERIC_PRECISION - NUMERIC_SCALE) / 9) * 4 + CASE (NUMERIC_PRECISION - NUMERIC_SCALE) % 9 WHEN 0 THEN 0 WHEN 1 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 2 WHEN 5 THEN 3 WHEN 6 THEN 3 WHEN 7 THEN 4 WHEN 8 THEN 4 END ) + (FLOOR(NUMERIC_SCALE / 9) * 4 + CASE NUMERIC_SCALE % 9 WHEN 0 THEN 0 WHEN 1 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 2 WHEN 5 THEN 3 WHEN 6 THEN 3 WHEN 7 THEN 4 WHEN 8 THEN 4 END ), NULL ) ) AS '存储字节长度' FROM information_schema.COLUMNS WHERE DATA_TYPE IN ('decimal', 'bigint') AND TABLE_SCHEMA = 'your_database_name'; -- 替换为你的数据库名 ``` 但是,请注意,这个查询只适用于decimalbigint类型,并且我们通过条件过滤了这两种类型。对于bigint,我们直接返回8(字节)。对于decimal,我们按照上述规则计算整数部分和小数部分的字节数然后相加。 另外,这个查询在计算整数部分位数时,如果NUMERIC_PRECISION - NUMERIC_SCALE为负数?但不会,因为小数位数不能大于精度。 考虑到查询的复杂度,如果用户只需要精度和标度,那么第一个查询更简单。因此,我们根据用户的需求提供两种方案。 由于用户的问题中提到了引用[1]中的“列字节长度”,所以这里我们假设用户需要的是存储字节长度。因此,我们提供第二种查询。 但是,注意:在information_schema中,还有另一种方法获取存储字节长度,即通过INNODB_SYS_COLUMNS表(如引用[2]所示),但这是InnoDB引擎特定的,而且需要权限访问这些表。另外,这些表在MySQL 5.6及以上版本中可用,但通常我们使用标准的information_schema.COLUMNS表。 引用[2]中列出了InnoDB系统表,其中包含`INNODB_SYS_COLUMNS`,它的`len`列表示字节长度。所以,如果我们只需要InnoDB表的列,并且有权限访问这些表,我们可以这样查询: ```sql SELECT t.NAME AS '表名', c.NAME AS '字段名', c.LEN AS '存储字节长度' FROM information_schema.INNODB_SYS_COLUMNS c JOIN information_schema.INNODB_SYS_TABLES t ON c.TABLE_ID = t.TABLE_ID WHERE t.NAME = 'your_database_name/your_table_name' -- 注意:这里的表名格式是'database/table' AND c.NAME = 'your_column_name'; ``` 但是,这种方法只适用于InnoDB表,而且表名格式是`database/table`。另外,这个查询只能获取单个表单个字段的信息,不方便批量查询。 因此,综合考虑,如果用户需要的是存储字节长度,且数据库中的表都是InnoDB引擎,并且希望查询更简单,可以使用`INNODB_SYS_COLUMNS`表。否则,我们使用第二种复杂的查询来计算decimal类型存储字节长度。 由于用户的问题没有明确说明表的引擎,我们提供两种方法,并推荐使用第一种复杂的查询(基于information_schema.COLUMNS表)因为它适用于所有引擎(但注意,计算规则仅适用于decimal类型,其他数字类型如int、float等需要另外的规则)。 因此,总结回答: 要查询decimalbigint类型字段的长度信息(存储字节长度),可以使用以下两种方法之一: 方法一:通过information_schema.COLUMNS表计算(适用于所有引擎,但计算复杂) 方法二:通过INNODB_SYS_COLUMNS表直接获取(仅适用于InnoDB表) 我们分别给出两个示例: 方法一示例(计算存储字节长度): ```sql SELECT TABLE_SCHEMA AS '数据库名', TABLE_NAME AS '表名', COLUMN_NAME AS '字段名', DATA_TYPE AS '数据类型', CASE DATA_TYPE WHEN 'bigint' THEN 8 WHEN 'decimal' THEN (FLOOR((NUMERIC_PRECISION - NUMERIC_SCALE) / 9) * 4 + ELT((NUMERIC_PRECISION - NUMERIC_SCALE) % 9 + 1, 0,1,1,2,2,3,3,4,4) ) + (FLOOR(NUMERIC_SCALE / 9) * 4 + ELT(NUMERIC_SCALE % 9 + 1, 0,1,1,2,2,3,3,4,4) ) -- 注意:ELT函数第一个参数是索引(从1开始),所以余数0对应索引1,值为0;余数1对应索引2,值为1;...余数8对应索引9,值为4。 -- 但是,当余数为0时,%9的结果是0,那么ELT(0+1)=ELT(1)=0;余数为1时,ELT(2)=1;...余数为8时,ELT(9)=4。 -- 这样写比CASE表达式简洁一些,但可读性可能稍差。 ELSE NULL END AS '存储字节长度' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_database_name' AND DATA_TYPE IN ('decimal', 'bigint'); ``` 这里使用了`ELT`函数来简化CASE表达式的冗长。`ELT(N, str1, str2, ...)`返回第N个字符串,N从1开始。 方法二示例(仅InnoDB表): ```sql SELECT t.NAME AS '表名', c.NAME AS '字段名', c.LEN AS '存储字节长度' FROM information_schema.INNODB_SYS_COLUMNS c JOIN information_schema.INNODB_SYS_TABLES t ON c.TABLE_ID = t.TABLE_ID JOIN information_schema.TABLES tb ON t.NAME = CONCAT(tb.TABLE_SCHEMA, '/', tb.TABLE_NAME) AND tb.TABLE_SCHEMA = 'your_database_name' WHERE tb.TABLE_SCHEMA = 'your_database_name'; ``` 注意:方法二需要MySQL版本在5.6及以上,并且需要具有访问`information_schema.INNODB_SYS_*`表的权限。 最后,根据用户的具体需求选择合适的方法。如果用户只需要精度和标度,那么第一个简单查询即可。 由于问题中用户要求的是“长度信息”,而长度信息可能有多种含义,因此我们提供了多种方案。用户可以根据需要选择。 考虑到用户可能更关心的是定义的长度(即精度和标度),我们首先提供查询精度和标度的方法。如果用户需要存储字节长度,再提供后面的方法。 因此,我们最终回答如下: 要查询decimalbigint类型字段的精度和标度(即定义的长度): ```sql SELECT TABLE_SCHEMA AS '数据库名', TABLE_NAME AS '表名', COLUMN_NAME AS '字段名', DATA_TYPE AS '数据类型', NUMERIC_PRECISION AS '精度', NUMERIC_SCALE AS '标度' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_database_name' AND DATA_TYPE IN ('decimal', 'bigint'); ``` 对于bigint类型,标度(NUMERIC_SCALE)为0,精度(NUMERIC_PRECISION)为19(有符号)或20(无符号)。对于decimal类型,精度和标度由定义决定。 如果用户需要存储字节长度,则根据表的存储引擎选择上述方法一或方法二。 注意:方法一中的计算规则仅适用于decimal类型bigint类型固定8字节。其他数字类型(如int、float等)需要另外的计算规则,这里不展开。 希望这能解决用户的问题。</think>在 MySQL 的 `information_schema` 中,要查询 `decimal` 和 `bigint` 类型字段的长度信息,可以通过 `COLUMNS` 表中的以下列获取: ### 查询方法 ```sql SELECT TABLE_SCHEMA AS '数据库', TABLE_NAME AS '表名', COLUMN_NAME AS '字段名', DATA_TYPE AS '数据类型', NUMERIC_PRECISION AS '精度', NUMERIC_SCALE AS '小数位数', CASE WHEN DATA_TYPE = 'bigint' THEN 8 -- bigint 固定 8 字节 WHEN DATA_TYPE = 'decimal' THEN (FLOOR(NUMERIC_PRECISION/9)*4 + CASE NUMERIC_PRECISION%9 WHEN 0 THEN 0 WHEN 1 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 2 WHEN 5 THEN 3 WHEN 6 THEN 3 WHEN 7 THEN 4 WHEN 8 THEN 4 END) ELSE NULL END AS '存储字节长度' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_database' -- 替换为你的数据库名 AND DATA_TYPE IN ('decimal', 'bigint'); ``` ### 关键字段说明: 1. **`NUMERIC_PRECISION`** - 数字类型的总精度(总位数) - `decimal(10,2)` → 10 - `bigint` → 19(有符号)或 20(无符号) 2. **`NUMERIC_SCALE`** - 小数点后的位数(仅对 decimal 有效) - `decimal(10,2)` → 2 - `bigint` → 0 3. **存储字节长度计算**: - **bigint**:固定 **8 字节** - **decimal**:根据精度计算存储空间[^1]: ```math \text{字节长度} = \left\lfloor \frac{\text{精度}}{9} \right\rfloor \times 4 + \begin{cases} 0 & \text{余数} = 0 \\ 1 & \text{余数} = 1,2 \\ 2 & \text{余数} = 3,4 \\ 3 & \text{余数} = 5,6 \\ 4 & \text{余数} = 7,8 \end{cases} ``` 示例: - `decimal(10,2)` → 精度 10:$\lfloor10/9\rfloor=1$ → $1×4=4$,余数 $1$ → $+1$ = **5 字节** - `decimal(18,4)` → 精度 18:$\lfloor18/9\rfloor=2$ → $2×4=8$,余数 $0$ → **8 字节** ### 查询示例结果: | 数据库 | 表名 | 字段名 | 数据类型 | 精度 | 小数位数 | 存储字节长度 | |-------|------|--------|----------|------|----------|--------------| | sales | orders | amount | decimal | 10 | 2 | 5 | | users | account | id | bigint | 19 | 0 | 8 | ### 引擎特定查询(仅 InnoDB) 若需直接获取 InnoDB 引擎的内部存储字节长度: ```sql SELECT c.NAME AS '字段名', c.LEN AS '存储字节长度' FROM information_schema.INNODB_SYS_COLUMNS c JOIN information_schema.INNODB_SYS_TABLES t ON c.TABLE_ID = t.TABLE_ID WHERE t.NAME = 'your_database/your_table' -- 格式: 数据库名/表名 AND c.NAME = 'your_column'; ``` ### 注意事项: 1. `bigint` 的精度固定为 19(有符号)或 20(无符号) 2. `decimal` 的存储空间取决于精度,与小数位数无关 3. InnoDB 系统表(如 `INNODB_SYS_COLUMNS`)仅显示物理存储长度[^2] 4. 所有数字类型的长度信息都存储在 `information_schema.COLUMNS` 中[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值