数据库临时表实现不同数据源的联合字段检查

背景:

业务数据源有mdb格式(文件型数据库),shp格式(存储地理实体信息)

一开始,产品的同学让我做个命令检查图层字段,我直接写完可以用了。因为客户单位检查项的增加,又要做个命令来检查另外一个图层的另外的字段。我发现这五六个需求都是类似的。于是就想将业务检查需求做为一个sql语句,查询结果就是不符合检查需求的数据。
//因为shp不支持sql的查询,于是设计了创建临时表的方式满足繁杂的业务质检的需求。

//可能涉及mdb的若干个二维表与shp文件的若干个图层的检查。
//二维表与图层可混查,在sql语句中,图层名前面加TEMP_以区分。
//为了提升性能,临时表的字段只有使用到的字段,不是图层所有字段。

于是,最终只有一个命令,可以使用sql来进行二维表与图层的混合字段检查,产品的同学根据需求去编辑不同的sql质检语句即可。

目录

背景:

一,取出查询的字段和表

二,从表名列表获取需要创建的临时表名

 三,截取所有表及其需要的字段

四,创建临时表

 五,执行sql语句

六,删除临时表


一,取出查询的字段和表

//查询的字段列表(需要输出的)m_fieldList(qstringlist)
//查询涉及的表的列表 m_tableList(qstringlist)


	if ("SELECT" != m_dataViewSql.left(6).toUpper())
	{
		printf(QString("只支持SELECT查询[%1]").arg(m_dataViewSql));
		return;
	}
	else
	{
		m_dataViewSql = m_dataViewSql.toUpper();
		int indexStart = m_dataViewSql.indexOf("SELECT") + 6;
		int indexEnd = m_dataViewSql.indexOf("FROM");
		QString fields = m_dataViewSql;
		if (-1 != indexEnd)
		{
			fields = m_dataViewSql.left(indexEnd - 1);
		}
		fields = fields.right(fields.size() - indexStart).trimmed();
		if ("*" == fields)
		{
			printf(QString("暂不支持*查询[%1]").arg(m_dataViewSql));
			return;
		}

		m_fieldList = fields.split(",");
		for (int i = 0; i < m_fieldList.size(); ++i)
		{
			QString field = m_fieldList.at(i).trimmed();
			int index = field.indexOf(".");
			if (-1 != index)
			{
				m_fieldList[i] = field.right(field.size() - index - 1);
			}
		}

		//从多个from后取得所有表名
		indexStart = 0;
		while (1)
		{
			indexEnd = m_dataViewSql.indexOf("FROM", indexStart);
			if (-1 == indexEnd)
			{
				break;
			}
			indexStart = indexEnd + 4;
			indexEnd = m_dataViewSql.indexOf("WHERE", indexStart);
			QString tables = m_dataViewSql;
			if (-1 != indexEnd)
			{
				tables = m_dataViewSql.left(indexEnd - 1);
			}
			tables = tables.right(tables.size() - indexStart).trimmed();
			QStringList tablenames = tables.split(",");
			for (int i = 0; i < tablenames.size(); ++i)
			{
				QString srcData = tablenames.at(i);
				QString name = cutTempName(srcData, 0, true);
				if (!name.isEmpty() && -1 == m_tableList.indexOf(name))
				{
					m_tableList.append(name);
				}
			}
		}

		if (m_fieldList.empty())
		{
			printf("查询的字段为空");
			return;
		}
	}

二,从表名列表获取需要创建的临时表名

存到列表中: m_tempFieldmap


	for (int i = 0; i < m_tableList.size(); ++i)
	{
		QString tableName = m_tableList.at(i);
		if ("TEMP_" == tableName.left(5))
		{
			QString tName = tableName.right(tableName.size() - 5);
			m_tempTableList.append(tName);
			QStringList fields;
			m_tempFieldmap.insert(tName, fields);
		}
	}

 三,截取所有表及其需要的字段


	if (m_tempTableList.size())
	{
		int index = 0;
		int iStart = 0;
		while (1)
		{
			index = m_dataViewSql.indexOf("TEMP_", index);
			if (index != -1)
			{
				QString TempName = cutTempName(m_dataViewSql, index);
				if (!TempName.isEmpty())
				{
					QStringList tempNameAndField = TempName.split(".");
					if (tempNameAndField.size() == 2)
					{
						QString tempTable = tempNameAndField.at(0);
						tempTable = tempTable.right(tempTable.size() - 5);
						QString tempFeild = tempNameAndField.at(1);
						if (-1 == m_tempFieldmap[tempTable].indexOf(tempFeild))
						{
							m_tempFieldmap[tempTable].append(tempFeild);
						}
					}
				}
				index += 5;
			}
			else
			{
				break;
			}
		}
	}

四,创建临时表

//逐个建表插入数据
	for (int i = 0; i < m_tempTableList.size(); ++i)
	{
		g_pInterface->iDataSetProgressValue(i + 1, m_tempTableList.size());
		if (createTable(m_tempTableList.at(i)))
		{
			writeTable(m_tempTableList.at(i));
		}
	}

bool createTable(const QString &layerName)
{
	Layer *pLayer = nullptr;
	QString layName = m_szqDM + layerName;
	g_pInterface->GetLayer(pLayer, layName);
	if (nullptr == pLayer)
	{
		printf(QString("获取图层[%1]打开失败!").arg(layName));
		return false;
	}

	QStringList needField = m_tempFieldmap[layerName];	//所需建表的字段名称列表
	QString tableFields;	//sql括号内

	 Fields *pFields = pLayer->Fields();
    //遍历需要建表的字段,映射到mdb的字段类型
	for (int i = 0; i < needField.size(); ++i)
	{
		QString field = needField.at(i);
		 Field *pfield = pFields->field(field);
		if (pfield == nullptr)
		{
			printf(QString("图层[%1]无拓展属性[%2]").arg(layerName).arg(field));
			continue;
		}
		int length = pfield->Length();
		int type = pfield->filedType();
		QString acessSqlType;
		switch (type)
		{
		case QVariant::Bool:
			acessSqlType = "BIT";
			break;
		case QVariant::Int:
			acessSqlType = "INT";
			break;
		case QVariant::LongLong:
			acessSqlType = "INTEGER";
			break;
		case QVariant::Double:
			acessSqlType = "FLOAT";
			break;
		case QVariant::Char:
		case QVariant::String:
			acessSqlType = QString("CHAR(%1)").arg(length);
			break;
		case QVariant::DateTime:
		case QVariant::Date:
			acessSqlType = "DATETIME";
			break;
		default:
			printf(QString("未配置类型[%1]").arg(type));
			acessSqlType = "SMALLINT";
			break;
		}
		tableFields += field + " " + acessSqlType + ",";
	}

	if (tableFields.isEmpty())
	{
		printf(QString("图层[%1]无拓展属性,不创建临时表。").arg(layerName));
		return false;
	}
	tableFields = tableFields.left(tableFields.size() - 1);

	QString CreatTempTableSql = QString("CREATE TABLE TEMP_%1 (ENTITYPOINT CHAR(16), %2)")
		.arg(layerName).arg(tableFields);

	if (m_sqlQuery.exec(CreatTempTableSql))
	{
		//printf(QString("sql[%1]建表成功!").arg(CreatTempTableSql));
	}
	else
	{
		//先输出建表错误信息,否则会被覆盖
		QString strErrors = m_sqlQuery.lastError().text();
		//printf(QString("执行sql[%1]失败!").arg(CreatTempTableSql));
		printf(strErrors);

		QString dropTableSql = "DROP TABLE TEMP_" + layerName + " ";
		if (!m_sqlQuery.exec(dropTableSql))
		{
			QString strErrors = m_sqlQuery.lastError().text();
			//printf(QString("执行sql[%1]失败!").arg(CreatTempTableSql));
			printf(strErrors);
		}
		return false;
	}

	return true;
}

void writeTable(const QString &layerName)
{
	Layer *pLayer = nullptr;
	QString layName = m_szqDM + layerName;
	GetLayer(pLayer, layName);
	if (nullptr == pLayer)
	{
		printf(QString("获取图层[%1]打开失败!").arg(layName));
		return;
	}

    //组prepare sql,在最前面加上实体指针,后续查询结果需要使用到
	QStringList needField = m_tempFieldmap[layerName];	//所需建表的字段名称列表
	QString tableFields = "ENTITYPOINT,";	//实体指针
	QString questions = "?,";

	for (const QString &field : needField)
	{
		tableFields += field + ",";
		questions += "?,";
	}

	if (tableFields.length() <= 16)
	{
		printf(QString("%1无拓展属性").arg(layName));
		return;
	}
	tableFields = tableFields.left(tableFields.length() - 1);
	questions = questions.left(questions.length() - 1);

	QString insertSql = QString("INSERT INTO TEMP_%1(%2) VALUES(%3) ").arg(layerName).arg(tableFields).arg(questions);
	m_sqlQuery.prepare(insertSql);

	//开事务
	if (!m_targetdb.transaction())
	{
		printf("writeTable Error 354. " + m_targetdb.lastError().text());
		return;
	}
	QList< Entity *> pEntList = pLayer->items();
	int step = 0;
	for ( Entity *pEnt : pEntList)
	{
		qlonglong longEnt = (qlonglong)pEnt;
		m_sqlQuery.addBindValue(QString::number(longEnt));
		//printf(QString("实体指针测试写表[%1]").arg(QString::number(longEnt)));

		for (const QString &field : needField)
		{
			QString data = pEnt->getXData(field).toString();
			m_sqlQuery.addBindValue(data);
		}

		if (m_sqlQuery.exec())
		{
			//printf(QString("执行sql[%1]成功!").arg(insertSql));
		}
		else
		{
			QString strErrors = m_sqlQuery.lastError().text();
			//printf(QString("执行sql[%1]失败!").arg(insertSql));
			printf(strErrors);
			break;
		}
	}
	//提交
	if (!m_targetdb.commit())
	{
		printf("writeTable Error 385. " + m_targetdb.lastError().text());
		//回滚
		if (!m_targetdb.rollback())
		{
			printf("writeTable Error 389. " + m_targetdb.lastError().text());
		}
	}
}

 五,执行sql语句

在查询结果里将检查结果输出。

	runSQL(m_dataViewSql);

void runSQL(const QString &sql)
{
	QString strSql = sql;
	//如果是图层,查询加上实体指针。否则不用修改,直接执行
	if (m_isLayer)
	{
		strSql = "SELECT " + m_LayerName + ".ENTITYPOINT, " + strSql.right(strSql.size() - 7);
	}

	if (m_sqlQuery.exec(strSql))
	{
		while (m_sqlQuery.next())
		{
			//取出结果,按业务需求写数据。
			QVariantList dataViewData;
			iDataEntity *pEnt;
			QString dataEntpStr;
			QString fieldData;
			if (m_isLayer)
			{
				if (m_sqlQuery.value("ENTITYPOINT").isValid())
				{
					dataEntpStr = m_sqlQuery.value("ENTITYPOINT").toString().trimmed();
					pEnt = (iDataEntity *)(dataEntpStr.toLongLong());
				}
			}
			
			//写入继承属性
			QString fieldName;
			for (int i = 0; i < m_fieldList.size(); ++i)
			{
				fieldName = m_fieldList.at(i);
				if (m_sqlQuery.value(fieldName).isValid())
				{
					fieldData = m_sqlQuery.value(fieldName).toString().trimmed();
				}
				dataViewData.append(fieldData);
			}
			//后面略
			。
			。
			。
			。
		}
	}
	else
	{
		QString strErrors = m_sqlQuery.lastError().text();
		printf(strErrors);
	}
}

六,删除临时表

	for (int i = 0; i < m_tempTableList.size(); ++i)
	{
		deleteTable(m_tempTableList.at(i));
	}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值