法:
COUNT(DISTINCT expr ,[expr ...])
函数使用说明:返回不同的非NULL 值数目。若找不到匹配的项,则COUNT(DISTINCT) 返回 0
Mysql的查询结果行字段拼接,可以用下面两个函数实现:
1. concat函数
mysql> select concat('1','2','3') from test ;
+---------------------+
| concat('1','2','3') |
+---------------------+
| 123 |
+---------------------+
如果连接串中存在NULL,则返回结果为NULL:
mysql> select concat('1','2',NULL,'3') from test ;
+--------------------------+
| concat('1','2',NULL,'3') |
+--------------------------+
| NULL |
+--------------------------+
2. concat_ws函数
concat(separator,str1,str2,...) 代表 concat with separator ,是concat()的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。
mysql> select concat_ws(':','1','2','3') from test ;
+----------------------------+
| concat_ws(':','1','2','3') |
+----------------------------+
| 1:2:3 |
+----------------------------+
分隔符为NULL,则返回结果为NULL:
mysql> select concat_ws(NULL,'1','2','3') from test; +-----------------------------+ | concat_ws(NULL,'1','2','3') | +-----------------------------+ | NULL | +-----------------------------+
如果参数中存在NULL,则会被忽略:
mysql> select concat_ws(':','1','2',NULL,NULL,NULL,'3') from test ;
+-------------------------------------------+
| concat_ws(':','1','2',NULL,NULL,NULL,'3') |
+-------------------------------------------+
| 1:2:3 |
+-------------------------------------------+
可以对NULL进行判断,并用其它值进行替换:
mysql> select concat_ws(':','1','2',ifNULL(NULL,'0'),'3') from bank limit 1;
+---------------------------------------------+
| concat_ws(':','1','2',ifNULL(NULL,'0'),'3') |
+---------------------------------------------+
| 1:2:0:3 |
+---------------------------------------------+
concat的SQL注入:
select username,email,content from test_table where user_id=uid;
上面的user_id是接收输入的。
concat函数本来是这样用的SELECT CONCAT('My', 'S', 'QL');执行结果是'MySQL'。也就是连接作用的。我们利用它来为我们服务,
uid=-1 union select username ,concat(password,sex,address,telephone),content from test_table where user_id=管理员id;
这个语句实际查询了六个字段,但是显示的时候,把password,sex,address,telephone等字段合在一起,显示在原本应该显示email的地方。
感谢阅读,如果这篇文章帮助了您,欢迎 点赞 ,收藏,关注,转发 哟。您的帮助是我们前行的动力,我们会提供更多有价值的内容给大家... 谢谢!
格语法:
注意:颜色使用格式有三种:rgb(x,x,x) #xxxxxx colorname
<table width=""></table>指定表格的宽度大小(使用数字pixel或%)
<table border=""></table>设定表格边框大小(使用数字pixel)
<table align=""></table>表格位置,置左,为默认值
align属性:left(左对齐表格,默认值)、right(右对齐表格)、center(居中对齐表格)
<table bgcolor=""></table>设定表格的背景颜色
<table cellpadding=""></table>指定内容与网格线之间的间距(使用数字pixel或%)
<table cellspacing=""></table>指定网格线与网格线之间的距离(使用数字pixel或%)
<table border="1" cellspacing="0" cellpadding="0">
通常表格, 这两个参数都设置为 0 。
<table rules="rows"></table>规定内侧边框的哪个部分是可见的。(兼容性差)
rules属性:none 没有线条。
groups 位于行组和列组之间的线条。
rows 位于行之间的线条。
cols 位于列之间的线条。
all 位于行和列之间的线条。
<table summary="Monthly savings for the Flintstones family"></table>
定义了表格内容的摘要:
表格结构:
在使用表格进行布局时, 可以将表格划分为头部、主体和页脚, 具体如下所示:
<thead></thead>:用于定义表格的头部, 必须位于<table></table>标记中, 一般包含网页的logo和导航等头部信息。
<tfoot></tfoot>:用于定义表格的页脚, 位于<table></table>标记中<thead></thead>标记之后, 一般包含网页底部的企业信息等。
<tbody></tbody>:用于定义表格的主体, 位于<table></table>标记中<tfoot></tfoot>标记之后, 一般包含网页中除头部和底部之外的其他内容。
注意:在没有<tbody></tbody>比较的情况下, 浏览器会自动添加<tbody></tbody>标记。
<table bordercolor=""></table>设定表格边框的颜色
<table cols=""></table>指定表格的栏数
<table height=""></table>指定表格的高度大小(使用数字)
<table background=""></table>背景图片的URL=就是路径网址(默认是repeat:水平和垂直方向重复)
<table bordercolordark=""></table>设定表格暗边框的颜色
<table bordercolorlight=""></table>设定表格亮边框的颜色
<tr align=""></tr> 定义表格行的内容对齐方式。
align属性值:right、left、center、justify、char
<tr bgcolor=""></tr> 规定表格行的背景颜色。
<tr valign=""></tr> 规定表格行中内容的垂直对齐方式。
valign属性值right、left、center、justify、char
<td colspan=""></td>指定储存格合并栏的栏数(使用数字)
<td rowspan=""></td>指定储存格合并列的列数(使用数字)
<td align=""></td> 调整表格字段之左右对齐
<td bgcolor=""></td> 设定表格字段之背景颜色
<td colspan="" rowspan=""></td> 表格字段的合并
<td valign=""></td> 调整表格字段之上下对齐
<td width=""></td> 调整表格字段宽度
<td nowrap="nowrap"></td> 规定表格单元格中的内容不换行(注意只有一个值:nowrap)
<caption></caption>为表格加上标题
<caption align="">设定表格标题位置
align属性:left, center(默认值), right
<th></th> 定义表头(粗体居中)
细表格边框
<table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="158" height="68">
<tr>
<td width="158" height="68"></td>
</tr>
</table>表格创建后浏览器会自动添加<tbody>标签
阅读本文大概需要 6 分钟
日常开发软件可能会遇到这类小众需求,导出数据到 Word、Excel 以及 PDF文件,如果你使用 C++ 编程语言,那么可以选择的方案不是很多,恰好最近刚好有这部分需求,整理下这段时间踩过的坑,方便后人
日常开发的软件使用最多的应该是导出数据到 Word 文档中,目前可以用的方案有这几种
没有十全十美的方案,任何方案都存在优点和缺点,下面来详细看下这几种方案的优缺点以及适用场景
“
原理:事先编辑好一份 Word 模板,需要替换内容的 地方预留好位置,然后使用特殊字段进行标记,后面使用代码进行全量替换即可完成
我们先编辑一份 Word 模板文档,内容大概如下所示:
QFile file("XML-Template.xml");
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "open xxml file fail. " << file.errorString();
return 0;
}
QByteArray baContent=file.readAll();
file.close();
QString strAllContent=QString::fromLocal8Bit(baContent);
strAllContent.replace("$VALUE0", "1");
strAllContent.replace("$VALUE1", QString::fromLocal8Bit("法外狂徒张三"));
strAllContent.replace("$VALUE2", QString::fromLocal8Bit("考试不合格"));
strAllContent.replace("$VALUE3", "2");
strAllContent.replace("$VALUE4", QString::fromLocal8Bit("李四"));
strAllContent.replace("$VALUE5", QString::fromLocal8Bit("合格"));
QFile newFile("export.doc");
if (!newFile.open(QIODevice::WriteOnly))
{
qDebug() << "file open fail." << newFile.errorString();;
return 0;
}
newFile.write(strAllContent.toLocal8Bit());
newFile.close();
可以看出来这种方式比较繁琐,重点是编辑固定的模板格式,而且编辑好后保存成XML格式后还需要继续调整,这种 XML 格式标签很多,不小心就修改错了,导致导出的文档打不开
这种方式适合模板内容不太复杂,内容较少的情况下使用
“
原理:采用 Micro Soft公开的接口进行通讯,进行读写时会打开一个 `Word进程来交互
COM 技术概述
Qt 为我们提供了专门进行交互的类和接口,使用 Qt ActiveX框架就可以很好的完成交互工作
使用时需要引入对应的模块,在 pro 文件引入模块
QT *=axcontainer
打开文档写入内容
QAxObject *pWordWidget=new(std::nothrow) QAxObject;
bool bResult=pWordWidget->setControl("word.Application");
if (!bResult)
{
return false;
}
// 设置是否显示
pWordWidget->setProperty("Visible", false);
QAxObject *pAllDocuments=pWordWidget->querySubObject("Documents");
if(nullptr==pAllDocuments)
{
return false;
}
// 新建一个空白文档
pAllDocuments->dynamicCall("Add (void)");
// 获取激活的文档并使用
QAxObject *pActiveDocument=pAllDocuments->querySubObject("ActiveDocument");
if(nullptr==pActiveDocument)
{
return false;
}
// 插入字符串
QAxObject *pSelectObj=pWordWidget->querySubObject("Selection");
if (nullptr !=pSelectObj)
{
pSelectObj->dynamicCall("TypeText(const QString&)", "公众号:devstone");
}
……
可以看出来使用起来不难,对于新手友好一点,很多写入操作方法比较繁琐,需要自己重新封装一套接口
这种方式同样适用于写入 Excel 文件,后面再说
“
原理:这种方式得益于 Word支持 HTML格式导出渲染显示,那么反向也可以支持,需要我们拼接 HTML格式内容,然后写入文件保存成 .doc格式
QString HTML2Word::getHtmlContent()
{
QString strHtml="";
strHtml +="<html>";
strHtml +="<head>";
strHtml +="<title>测试生成word文档</title>";
strHtml +="<head>";
strHtml +="<body style=\"bgcolor:yellow\">";
strHtml +="<h1 style=\"background-color:red\">测试qt实现生成word文档</h1>";
strHtml +="<hr>";
strHtml +="<p>这里是插入图片<img src=\"D:\\title.jpg" alt=\"picture\" width=\"100\" height=\"100\"></p>";
strHtml +="</hr>";
strHtml +="</body>";
strHtml +="</html>";
return strHtml;
}
// 保存写入文件
QFile file("D:/htmp2Word.doc");
if (!file.open(QIODevice::WriteOnly))
{
return false;
}
QTextStream out(&file);
out << getHtmlContent();
file.close();
这种方式难点在于 HTML格式拼接,任何缺失字段都会导致导出失败,适合小众需求下导出
图片问题其实可以手动进行转化,文档导出成功后手动拷贝内容到新的文档,这样图片就真正插入到文档中,文档发送给别人也不会丢失图片了
还有一个坑就是:如果你使用 WPS 打开导出的文档,默认显示的是 web视图,需要手动进行调整
某些电脑分辨率变化也会导致生成的文档中字体等产生变化
可以使用的第三方库几乎没有,网络上找到的有这么几个
DuckX库 docx库
在读写 Word这部分,C++ 基本没有可以使用的第三方库,不像其他语言Java、C#、Python有很多可以选择,这个痛苦也只有 C++ 程序员能够理解了吧
所以怎么选择还是看自己项目需求吧,没有十全十美的方案
上面说了这么多,都是导出生成 Wrod,那么下面来看看有那些方式可以读取显示 Word内容
这种需求应该不会很多,而且显示难度更大一些
使用 COM组件方式,即采用 QAxWidget框架显示 office 文档内容,本质上就是在我们编写的 Qt 界面上嵌入 office 的软件,这种方式其实和直接打开 Word查看没有啥区别,效果、性能上不如直接打开更好一些
目前一般都会采用折中方案,把 Word 转为 PDF 进行预览加载显示,我们知道 PDF 渲染库比较多,生态相对来说要好一些,在选择上就更广泛些,如何使用后面部分有专门介绍 PDF章节
目前有一个支持比较好的第三方库可以使用,整体使用基本可以满足日常使用
QXlsx
这款开源库支持跨平台,Linux、Windows、Mac、IOS、Android,使用方式支持动态库调用和源码直接集成,非常方便
编译支持 qmake和cmake,可以根据你自己的项目直接集成编译,读写速度非常快
QXlsx::Document xlsx;
// 设置一些样式
QXlsx::Format titleFormat;
titleFormat.setBorderStyle(QXlsx::Format::BorderThin); // 边框样式
titleFormat.setRowHeight(1,1,30); // 设置行高
titleFormat.setHorizontalAlignment(QXlsx::Format::AlignHCenter); // 设置对齐方式
// 插入文本
xlsx.write(1,1, "微信公众号:devstone", titleFormat);
// 合并单元格
xlsx.mergeCells(QXlsx::CellRange(2,1,4,4), titleFormat);
// 导出保存
xlsx.saveAs("D:/xlsx_export.xlsx");
// 添加工作表
xlsx.addSheet("devstone");
可以看到上手非常容易、各个函数命名也贴近 Qt Api,是一款非常良心的开源软件
“
PS:注意该软件使用 MIT 许可协议,这样对于很多个人或者公司来说非常良心,意味着你可以无偿使用、修改该项目,但是必须在你项目中也添加同样的 MIP许可
上面也提到了,还可以使用 COM 组件的方式读写 Excel,不过有了这款开源库基本就可以告别 COM组件方式了
PDF相关开源库挺多的,给了 C++ 程序员莫大的帮助,目前可用的主要有这些
其中 mupdf和 poppler 属于功能强大但是很难编译的那种,需要有扎实的三方库编译能力,否则面对 n 个依赖库会无从下手
不过可喜的是 Github 上有两个开源库可以供选择
这个库其实封装了 pdf.js库,使用 WebEngine来执行 JavaScript进而加载文件
项目地址
这种方式对环境有特殊要求了,如果你的项目使用的 Qt 版本不支持 WebEngine,那么就无法使用
这个库是 Qt 官方亲自操刀对第三方库进行了封装,暴露的 API 和 Qt 类似,使用起来非常舒服
Qt 官方
代码结构以及使用 Demo
关于如何使用,官方已经给了我们非常详细的步骤了,直接跟着下面几步就 OK 了
官方教程
git clone git://code.qt.io/qt-labs/qtpdf
cd qtpdf
git submodule update --init --recursive
qmake
make
cd examples/pdf/pdfviewer
qmake
make
./pdfviewer /path/to/my/file.pdf
可以看到使用了谷歌开源的 pdfium 三方库,编译时需要单独更新下载这个库,因为某些原因可能你无法下载,不过好在有人在 GitHub上同步了这个仓库的镜像,有条件还是建议直接下载最新稳定版的
可正常访问的仓库地址:https://github.com/PDFium/PDFium
相关类可以看这个文档:https://developers.foxit.com/resources/pdf-sdk/c_api_reference_pdfium/modules.html
“
最后还要注意项目开源协议:pdfium引擎开始来自于福昕,一个中国本土的软件公司,Google与其合作最终进行了开源,目前采用的是 BSD 3-Clause 协议,这种协议允许开发者自由使用、修改源代码,也可以修改后重新发布,允许闭源进行商业行为,不过需要你在发布的产品中包含原作者代码中的 BSD 协议
以上就是项目中常用的文档处理方法总结,当然了肯定也还有其它方案可以实现,毕竟条条大路通罗马,如果你还要不错的方案和建议欢迎留言
PS: 以上方案和对应的源码编译、使用例子会统一上传到 GitHub对应的仓库,方便后人使用
取之互联网、回报互联网
原创不易,如果觉得对你有帮助,欢迎点赞、在看、转发
推荐阅读
*请认真填写需求信息,我们会在24小时内与您取得联系。