500 lines
22 KiB
C#
500 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using CYQ.Data.Table;
|
|
using System.Data;
|
|
using CYQ.Data.Tool;
|
|
|
|
namespace CYQ.Data.SQL
|
|
{
|
|
/// <summary>
|
|
/// SQL 结构语句
|
|
/// </summary>
|
|
internal class SqlCreateForSchema
|
|
{
|
|
#region 获取CreateTable相关SQL语句
|
|
/// <summary>
|
|
/// 获取单个列的表描述语句
|
|
/// </summary>
|
|
internal static string GetTableDescriptionSql(string tableName, MCellStruct mcs, DataBaseType dalType, bool isAdd)
|
|
{
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.MsSql:
|
|
string spName = isAdd ? "sp_addextendedproperty" : "sp_updateextendedproperty";
|
|
return string.Format("exec {3} N'MS_Description', N'{0}', N'user', N'dbo', N'table', N'{1}', N'column', N'{2}'", mcs.Description, tableName, mcs.ColumnName, spName);
|
|
case DataBaseType.Oracle:
|
|
case DataBaseType.PostgreSQL:
|
|
case DataBaseType.DB2:
|
|
case DataBaseType.MySql:
|
|
case DataBaseType.FireBird:
|
|
case DataBaseType.DaMeng:
|
|
case DataBaseType.KingBaseES:
|
|
return string.Format("comment on column {0}.{1} is '{2}'", SqlFormat.Keyword(tableName, dalType), SqlFormat.Keyword(mcs.ColumnName, dalType), mcs.Description);
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取指定的表架构生成的SQL(Create Table)的说明语句
|
|
/// </summary>
|
|
internal static string CreateTableDescriptionSql(string tableName, MDataColumn columns, DataBaseType dalType)
|
|
{
|
|
string result = string.Empty;
|
|
string tbDescription = columns.Description.Replace("'", "''");
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.MsSql:
|
|
case DataBaseType.Oracle:
|
|
case DataBaseType.PostgreSQL:
|
|
case DataBaseType.MySql:
|
|
case DataBaseType.DB2:
|
|
case DataBaseType.FireBird:
|
|
case DataBaseType.DaMeng:
|
|
case DataBaseType.KingBaseES:
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (MCellStruct mcs in columns)
|
|
{
|
|
if (!string.IsNullOrEmpty(mcs.Description))
|
|
{
|
|
if (dalType == DataBaseType.MsSql)
|
|
{
|
|
sb.AppendFormat("exec sp_addextendedproperty N'MS_Description', N'{0}', N'user', N'dbo', N'table', N'{1}', N'column', N'{2}';\r\n", mcs.Description, tableName, mcs.ColumnName);
|
|
}
|
|
//else if (dalType == DataBaseType.Oracle || dalType == DataBaseType.DB2 || dalType == DataBaseType.FireBird || dalType == DataBaseType.DaMeng)
|
|
//{
|
|
// sb.AppendFormat("comment on column {0}.{1} is '{2}';\r\n", tableName.ToUpper(), mcs.ColumnName.ToUpper(), mcs.Description.Replace("'", "''"));
|
|
//}
|
|
else// if (dalType == DataBaseType.PostgreSQL)
|
|
{
|
|
sb.AppendFormat("comment on column {0}.{1} is '{2}';\r\n",
|
|
SqlFormat.Keyword(tableName, dalType), SqlFormat.Keyword(mcs.ColumnName, dalType), mcs.Description.Replace("'", "''"));
|
|
}
|
|
}
|
|
}
|
|
if (dalType == DataBaseType.MsSql)//增加表的描述
|
|
{
|
|
sb.AppendFormat("exec sp_addextendedproperty N'MS_Description', N'{0}', N'user', N'dbo', N'table', N'{1}';\r\n", tbDescription, tableName);
|
|
}
|
|
else if (dalType == DataBaseType.MySql)
|
|
{
|
|
sb.AppendFormat("alter table {0} comment = '{1}';\r\n", SqlFormat.Keyword(tableName, dalType), tbDescription);
|
|
}
|
|
//else// if (dalType == DataBaseType.Oracle || dalType == DataBaseType.DB2 || dalType == DataBaseType.FireBird || dalType == DataBaseType.DaMeng)
|
|
//{
|
|
// sb.AppendFormat("comment on table {0} is '{1}';\r\n",
|
|
// tableName.ToUpper(), tbDescription);
|
|
//}
|
|
else// if (dalType == DataBaseType.PostgreSQL)
|
|
{
|
|
sb.AppendFormat("comment on table {0} is '{1}';\r\n",
|
|
SqlFormat.Keyword(tableName, dalType), tbDescription);
|
|
}
|
|
result = sb.ToString().TrimEnd(';');
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取指定的表架构生成的SQL(Create Table)语句
|
|
/// </summary>
|
|
internal static string CreateTableSql(string tableName, MDataColumn columns, DataBaseType dalType, string version)
|
|
{
|
|
//需要大写的表名
|
|
//if (dalType == DataBaseType.FireBird || dalType == DataBaseType.DaMeng)
|
|
//{
|
|
// tableName = tableName.ToUpper();
|
|
//}
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.Txt:
|
|
case DataBaseType.Xml:
|
|
return columns.ToJson(true);
|
|
default:
|
|
string createSql = string.Empty;
|
|
createSql = "CREATE TABLE " + SqlFormat.Keyword(tableName, dalType) + " \n(";
|
|
|
|
//读取主键的个数,如果是联合主键,则不设置主键。
|
|
List<MCellStruct> primaryKeyList = new List<MCellStruct>();
|
|
foreach (MCellStruct column in columns)
|
|
{
|
|
if (column.IsPrimaryKey)
|
|
{
|
|
primaryKeyList.Add(column);
|
|
}
|
|
}
|
|
foreach (MCellStruct column in columns)
|
|
{
|
|
createSql += "\n " + GetKey(column, dalType, ref primaryKeyList, version);
|
|
}
|
|
if (primaryKeyList.Count > 0)
|
|
{
|
|
createSql += GetUnionPrimaryKey(dalType, primaryKeyList);
|
|
}
|
|
createSql = createSql.TrimEnd(',') + " \n)";
|
|
// createSql += GetSuffix(dalType);
|
|
if (dalType == DataBaseType.MySql)
|
|
{
|
|
if (createSql.IndexOf("CURRENT_TIMESTAMP") != createSql.LastIndexOf("CURRENT_TIMESTAMP"))
|
|
{
|
|
createSql = createSql.Replace("Default CURRENT_TIMESTAMP", string.Empty);//mysql不允许存在两个以上的CURRENT_TIMESTAMP。
|
|
}
|
|
}
|
|
primaryKeyList.Clear();
|
|
return createSql;
|
|
}
|
|
}
|
|
|
|
private static string GetKey(MCellStruct column, DataBaseType dalType, ref List<MCellStruct> primaryKeyList, string version)
|
|
{
|
|
string key = SqlFormat.Keyword(column.ColumnName, dalType);//列名。
|
|
//需要大写的列名
|
|
//if (dalType == DataBaseType.FireBird || dalType == DataBaseType.DaMeng)
|
|
//{
|
|
// key = key.ToUpper();
|
|
//}
|
|
|
|
DataGroupType group = DataType.GetGroup(column.SqlType);//数据库类型。
|
|
bool isAutoOrPKey = column.IsPrimaryKey || column.IsAutoIncrement;//是否主键或自增列。
|
|
if (dalType != DataBaseType.Access || !isAutoOrPKey || !column.IsAutoIncrement)
|
|
{
|
|
SqlDbType sdt = column.SqlType;
|
|
if (sdt == SqlDbType.DateTime && dalType == DataBaseType.MySql && Convert.ToString(column.DefaultValue) == SqlValue.GetDate)
|
|
{
|
|
column.SqlType = SqlDbType.Timestamp;
|
|
}
|
|
key += " " + DataType.GetDataType(column, dalType, version);
|
|
column.SqlType = sdt;
|
|
}
|
|
if (isAutoOrPKey)
|
|
{
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
if (primaryKeyList.Count == 0 || (!column.IsPrimaryKey && dalType == DataBaseType.MySql))//MySql 的自增必须是主键.
|
|
{
|
|
column.IsPrimaryKey = true;
|
|
primaryKeyList.Insert(0, column);
|
|
}
|
|
}
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.Access:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " autoincrement(1,1)";
|
|
}
|
|
else// 主键。
|
|
{
|
|
if (group == DataGroupType.Guid)//主键又是GUID
|
|
{
|
|
key += " default GenGUID()";
|
|
}
|
|
}
|
|
break;
|
|
case DataBaseType.MsSql:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " IDENTITY(1,1)";
|
|
}
|
|
else
|
|
{
|
|
if (group == DataGroupType.Guid)//主键又是GUID
|
|
{
|
|
key += " Default (newid())";
|
|
}
|
|
}
|
|
break;
|
|
case DataBaseType.Oracle:
|
|
if (Convert.ToString(column.DefaultValue) == SqlValue.Guid)//主键又是GUID
|
|
{
|
|
key += " Default (SYS_GUID())";
|
|
}
|
|
break;
|
|
case DataBaseType.Sybase:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " IDENTITY";
|
|
}
|
|
else
|
|
{
|
|
if (group == DataGroupType.Guid)//主键又是GUID
|
|
{
|
|
key += " Default (newid())";
|
|
}
|
|
}
|
|
break;
|
|
case DataBaseType.MySql:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " AUTO_INCREMENT";
|
|
if (!column.IsPrimaryKey)
|
|
{
|
|
primaryKeyList.Add(column);
|
|
}
|
|
}
|
|
break;
|
|
case DataBaseType.SQLite://sqlite的AUTOINCREMENT不能写在primarykey前,
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " PRIMARY KEY AUTOINCREMENT";
|
|
primaryKeyList.Clear();//如果有自增加,只允许存在这一个主键。
|
|
}
|
|
break;
|
|
case DataBaseType.PostgreSQL:
|
|
if (column.IsAutoIncrement && key.EndsWith("int"))
|
|
{
|
|
key = key.Substring(0, key.Length - 3) + "serial";
|
|
}
|
|
break;
|
|
case DataBaseType.DB2:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " GENERATED ALWAYS AS IDENTITY";
|
|
}
|
|
break;
|
|
case DataBaseType.FireBird:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " GENERATED BY DEFAULT AS IDENTITY";
|
|
}
|
|
break;
|
|
case DataBaseType.DaMeng:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " IDENTITY(1, 1)";
|
|
}
|
|
break;
|
|
case DataBaseType.KingBaseES:
|
|
if (column.IsAutoIncrement)
|
|
{
|
|
key += " AUTO_INCREMENT";
|
|
}
|
|
break;
|
|
}
|
|
key += " NOT NULL";
|
|
}
|
|
else
|
|
{
|
|
string defaultValue = string.Empty;
|
|
if (Convert.ToString(column.DefaultValue).Length > 0 && group != DataGroupType.Object)//默认值只能是基础类型有。
|
|
{
|
|
if (dalType == DataBaseType.MySql)
|
|
{
|
|
if ((group == DataGroupType.Text && (column.MaxSize < 1 || column.MaxSize > 8000)) || (group == DataGroupType.Date && key.Contains("datetime"))) //只能对TIMESTAMP类型的赋默认值。
|
|
{
|
|
goto er;
|
|
}
|
|
}
|
|
defaultValue = SqlFormat.FormatDefaultValue(dalType, column.DefaultValue, 1, column.SqlType);
|
|
if (!string.IsNullOrEmpty(defaultValue))
|
|
{
|
|
if (dalType == DataBaseType.MySql) { defaultValue = defaultValue.Trim('(', ')'); }
|
|
key += " Default " + defaultValue;
|
|
}
|
|
}
|
|
|
|
er:
|
|
if (dalType != DataBaseType.Access)
|
|
{
|
|
if (dalType == DataBaseType.Sybase && column.SqlType == SqlDbType.Bit)
|
|
{
|
|
if (string.IsNullOrEmpty(defaultValue))
|
|
{
|
|
key += " Default 0";
|
|
}
|
|
key += " NOT NULL";//Sybase bit 不允许为Null
|
|
}
|
|
else
|
|
{
|
|
if (column.IsCanNull && (dalType == DataBaseType.DB2 || dalType == DataBaseType.FireBird || dalType == DataBaseType.DaMeng || dalType == DataBaseType.KingBaseES)) { }//db2,firebird 不能用null,其它可以不需要null
|
|
else
|
|
{
|
|
key += column.IsCanNull ? " NULL" : " NOT NULL";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!string.IsNullOrEmpty(column.Description))
|
|
{
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.MySql:
|
|
key += string.Format(" COMMENT '{0}'", column.Description.Replace("'", "''"));
|
|
break;
|
|
}
|
|
}
|
|
return key + ",";
|
|
}
|
|
private static string GetUnionPrimaryKey(DataBaseType dalType, List<MCellStruct> primaryKeyList)
|
|
{
|
|
string suffix = "\n ";
|
|
suffix += "PRIMARY KEY (";
|
|
foreach (MCellStruct st in primaryKeyList)
|
|
{
|
|
string cName = SqlFormat.Keyword(st.ColumnName, dalType);
|
|
//switch (dalType)//大写
|
|
//{
|
|
// case DataBaseType.DaMeng:
|
|
// case DataBaseType.FireBird:
|
|
// cName = cName.ToUpper();
|
|
// break;
|
|
//}
|
|
suffix += cName + ",";
|
|
}
|
|
suffix = suffix.TrimEnd(',') + ")";
|
|
return suffix;
|
|
}
|
|
#endregion
|
|
|
|
#region 获取AlterTable相关SQL语句
|
|
|
|
/// <summary>
|
|
/// 获取指定的表架构生成的SQL(Alter Table)语句
|
|
/// </summary>
|
|
public static List<string> AlterTableSql(string tableName, MDataColumn columns, string conn)
|
|
{
|
|
List<string> sql = new List<string>();
|
|
string version = null;
|
|
DataBaseType dalType;
|
|
using (DalBase helper = DalCreate.CreateDal(conn))
|
|
{
|
|
helper.ChangeDatabaseWithCheck(tableName);//检测dbname.dbo.tablename的情况
|
|
if (!helper.TestConn(AllowConnLevel.Master))
|
|
{
|
|
helper.Dispose();
|
|
return sql;
|
|
}
|
|
dalType = helper.DataBaseType;
|
|
version = helper.Version;
|
|
}
|
|
MDataColumn dbColumn = TableSchema.GetColumns(tableName, conn);//获取数据库的列结构
|
|
if (dbColumn == null || dbColumn.Count == 0) { return sql; }
|
|
|
|
//开始比较异同
|
|
List<MCellStruct> primaryKeyList = new List<MCellStruct>();
|
|
string tbName = SqlFormat.Keyword(tableName, dalType);
|
|
string alterTable = "alter table " + tbName;
|
|
foreach (MCellStruct ms in columns)//遍历新的结构
|
|
{
|
|
string cName = SqlFormat.Keyword(ms.ColumnName, dalType);
|
|
if (ms.AlterOp != AlterOp.None)
|
|
{
|
|
bool isContains = dbColumn.Contains(ms.ColumnName);
|
|
AlterOp op = ms.AlterOp;
|
|
if ((op & AlterOp.Rename) != 0)
|
|
{
|
|
op = (AlterOp)(op - AlterOp.Rename);
|
|
#region MyRegion Rename
|
|
if (!string.IsNullOrEmpty(ms.OldName) && ms.OldName != ms.ColumnName && !isContains)
|
|
{
|
|
string oName = SqlFormat.Keyword(ms.OldName, dalType);
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.MsSql:
|
|
sql.Add("exec sp_rename '" + tbName + "." + oName + "', '" + ms.ColumnName + "', 'column'");
|
|
break;
|
|
case DataBaseType.Sybase:
|
|
sql.Add("exec sp_rename \"" + tableName + "." + ms.OldName + "\", " + ms.ColumnName);
|
|
break;
|
|
case DataBaseType.MySql:
|
|
sql.Add(alterTable + " change " + oName + " " + GetKey(ms, dalType, ref primaryKeyList, version).TrimEnd(','));
|
|
break;
|
|
case DataBaseType.Oracle:
|
|
|
|
sql.Add(alterTable + " rename column " + oName + " to " + cName);
|
|
break;
|
|
}
|
|
isContains = isContains || dbColumn.Contains(ms.OldName);
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
if (op == AlterOp.Drop)
|
|
{
|
|
#region MyRegion
|
|
if (isContains)
|
|
{
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.MsSql:
|
|
case DataBaseType.Access:
|
|
case DataBaseType.MySql:
|
|
case DataBaseType.Oracle:
|
|
if (dalType == DataBaseType.MsSql)
|
|
{
|
|
sql.Add(@"declare @name varchar(50) select @name =b.name from sysobjects b join syscolumns a on b.id = a.cdefault
|
|
where a.id = object_id('" + tableName + "') and a.name ='" + ms.ColumnName + "'if(@name!='') begin EXEC('alter table " + tableName + " drop constraint '+ @name) end");
|
|
}
|
|
sql.Add(alterTable + " drop column " + cName);
|
|
break;
|
|
case DataBaseType.Sybase:
|
|
sql.Add(alterTable + " drop " + cName);
|
|
break;
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
//else if (ms.AlterOp == AlterOp.Rename)
|
|
//{
|
|
|
|
//}
|
|
else if (op == AlterOp.AddOrModify)
|
|
{
|
|
//智能判断
|
|
if (isContains) // 存在,则修改
|
|
{
|
|
string alterSql = SqlFormat.Keyword(ms.ColumnName, dalType) + " " + DataType.GetDataType(ms, dalType, version);
|
|
//检测是否相同
|
|
MCellStruct dbStruct = dbColumn[ms.ColumnName] ?? dbColumn[ms.OldName];
|
|
if (dbStruct.IsCanNull != ms.IsCanNull || dbStruct.SqlType != ms.SqlType || dbStruct.MaxSize != ms.MaxSize || dbStruct.Scale != ms.Scale)
|
|
{
|
|
string modify = "";
|
|
switch (dalType)
|
|
{
|
|
case DataBaseType.Oracle:
|
|
case DataBaseType.Sybase:
|
|
modify = " modify ";
|
|
break;
|
|
case DataBaseType.MySql:
|
|
modify = " change " + cName + " ";
|
|
break;
|
|
case DataBaseType.MsSql:
|
|
case DataBaseType.Access:
|
|
case DataBaseType.PostgreSQL:
|
|
modify = " alter column ";
|
|
break;
|
|
}
|
|
if (ms.IsCanNull != dbStruct.IsCanNull)
|
|
{
|
|
alterSql += (ms.IsCanNull ? " NULL" : " NOT NULL");
|
|
}
|
|
sql.Add(alterTable + modify + alterSql);
|
|
}
|
|
}
|
|
else //不在,则添加
|
|
{
|
|
sql.Add(alterTable + " add " + GetKey(ms, dalType, ref primaryKeyList, version).TrimEnd(','));
|
|
if (!string.IsNullOrEmpty(ms.Description))
|
|
{
|
|
string description = SqlCreateForSchema.GetTableDescriptionSql(tableName, ms, dalType, true);
|
|
if (!string.IsNullOrEmpty(description))
|
|
{
|
|
sql.Add(description);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return sql;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|