最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#實現(xiàn)MySQL中Clickhouse建表語句的轉(zhuǎn)換工具

 更新時間:2025年10月15日 09:11:26   作者:weixin_30777913  
這篇文章主要為大家詳細(xì)介紹了如何使用C#實現(xiàn)MySQL中Clickhouse建表語句的轉(zhuǎn)換工具,文中的示例代碼簡潔易懂,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下

功能概覽

步驟功能是否實現(xiàn)
1解析 MySQL 建表語句,提取表名、字段、主鍵、索引、表注釋、字符集、存儲引擎等?
2將 MySQL 數(shù)據(jù)類型映射為 ClickHouse 數(shù)據(jù)類型?
3推導(dǎo) ClickHouse 表引擎、分區(qū)鍵(PARTITION BY)、排序鍵(ORDER BY)?
4轉(zhuǎn)換字段屬性(NULL/NOT NULL、DEFAULT、COMMENT、AUTO_INCREMENT)為 ClickHouse 字段定義?
5為 MySQL 的索引(KEY / UNIQUE / FULLTEXT)生成 ClickHouse 注釋(提示不支持)?
6匯總所有部分,生成完整、可執(zhí)行的 ClickHouse 建表語句?
7提取 MySQL 不兼容語法(如 FOREIGN KEY、CHARACTER SET、COLLATE、ENGINE)并生成提示注釋?
??整合為完整 C# 控制臺程序,帶示例輸入 / 輸出?

程序結(jié)構(gòu)

命名空間:MySqlToClickHouseConverter

類:

  • Program(含 Main 函數(shù))
  • 數(shù)據(jù)模型類:TableMeta、ColumnMetaPrimaryKeyMeta、IndexMetaForeignKeyMeta

功能函數(shù):

  • ParseMySqlCreateTable(解析 MySQL 建表語句)
  • MapMySqlTypeToClickHouse(類型映射)
  • GetClickHouseTableEngineAndKeys(推導(dǎo)引擎 / 排序 / 分區(qū))
  • MapColumnToClickHouseField(字段定義轉(zhuǎn)換)
  • GenerateIndexComment(索引提示注釋)
  • ExtractAndConvertUnsupportedMySqlSyntax(其它語法提示)
  • GenerateClickHouseCreateTableStatement(匯總生成最終建表語句)

完整 C# 控制臺程序代碼(可直接復(fù)制到 Visual Studio 或 VS Code 運行)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace MySqlToClickHouseConverter
{
    // ========== 數(shù)據(jù)模型定義 ==========

    public class TableMeta
    {
        public string TableName { get; set; }
        public string TableComment { get; set; }
        public List<ColumnMeta> Columns { get; set; } = new();
        public PrimaryKeyMeta PrimaryKey { get; set; }
        public List<IndexMeta> UniqueKeys { get; set; } = new();
        public List<IndexMeta> Indexes { get; set; } = new();
        public List<ForeignKeyMeta> ForeignKeys { get; set; } = new();
        public string CharacterSet { get; set; }
        public string Collation { get; set; }
        public string Engine { get; set; }
    }

    public class ColumnMeta
    {
        public string Name { get; set; }
        public string DataType { get; set; }      // 原始 MySQL 類型,如 "int(11)"
        public string ClickHouseType { get; set; } // 映射后的 ClickHouse 類型,由 Step 2 填入
        public bool IsNullable { get; set; }
        public string DefaultValue { get; set; }
        public string Comment { get; set; }
        public bool IsAutoIncrement { get; set; }
    }

    public class PrimaryKeyMeta
    {
        public List<string> Columns { get; set; } = new();
    }

    public class IndexMeta
    {
        public string Name { get; set; }
        public bool IsUnique { get; set; }
        public bool IsFullText { get; set; }
        public List<string> Columns { get; set; } = new();
    }

    public class ForeignKeyMeta
    {
        public string Column { get; set; }
        public string ReferencedTable { get; set; }
        public string ReferencedColumn { get; set; }
    }

    // ========== 主程序入口 ==========
    class Program
    {
        static void Main(string[] args)
        {
            // ?? 示例 MySQL 建表語句(可直接替換為你自己的)
            string mySqlCreateTable = @"
                CREATE TABLE `users` (
                  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',
                  `name` varchar(100) NOT NULL COMMENT '用戶名',
                  `age` int(11) DEFAULT NULL COMMENT '年齡',
                  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
                  PRIMARY KEY (`id`),
                  UNIQUE KEY `uk_name` (`name`),
                  KEY `idx_age` (`age`),
                  FOREIGN KEY (user_id) REFERENCES profile(id),
                  COMMENT='用戶信息表',
                  ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                )";

            // --- Step 1: 解析 MySQL 建表語句 ---
            TableMeta table = ParseMySqlCreateTable(mySqlCreateTable);

            // --- Step 2: 映射字段類型 ---
            foreach (var col in table.Columns)
            {
                col.ClickHouseType = MapMySqlTypeToClickHouse(col.DataType);
            }

            // --- Step 3: 推導(dǎo)表引擎、分區(qū)鍵、排序鍵 ---
            var engineInfo = GetClickHouseTableEngineAndKeys(
                primaryKey: string.Join(", ", table.PrimaryKey?.Columns ?? new List<string>()),
                columns: table.Columns,
                tableName: table.TableName);

            // --- Step 4: 轉(zhuǎn)換字段定義 ---
            var columnDefinitions = table.Columns
                .Select(c => MapColumnToClickHouseField(c, c.ClickHouseType))
                .ToList();

            // --- Step 5: 生成索引提示注釋 ---
            var indexComments = new List<string>();
            foreach (var idx in table.Indexes)
            {
                indexComments.Add(GenerateIndexComment(idx));
            }
            foreach (var uq in table.UniqueKeys)
            {
                indexComments.Add(GenerateIndexComment(new IndexMeta
                {
                    Name = uq.Name,
                    IsUnique = true,
                    Columns = uq.Columns
                }));
            }

            // --- Step 6: 提取其它不兼容語法(FOREIGN KEY, CHARSET, ENGINE...)---
            var unsupportedSyntaxComments = ExtractAndConvertUnsupportedMySqlSyntax(mySqlCreateTable);

            // --- Step 7: 生成完整的 ClickHouse 建表語句 ---
            string clickHouseSql = GenerateClickHouseCreateTableStatement(
                tableName: table.TableName,
                tableComment: table.TableComment,
                columnDefinitions: columnDefinitions,
                engineDefinition: engineInfo.Engine,
                partitionByDefinition: engineInfo.PartitionBy,
                orderByDefinition: engineInfo.OrderBy,
                indexComments: indexComments,
                unsupportedSyntaxComments: unsupportedSyntaxComments);

            // ===== 輸出最終結(jié)果 =====
            Console.WriteLine("===== 轉(zhuǎn)換后的 ClickHouse 建表語句 =====");
            Console.WriteLine(clickHouseSql);
        }

        // ========== Step 1: 解析 MySQL 建表語句(簡化版,正則/關(guān)鍵字匹配)==========
        static TableMeta ParseMySqlCreateTable(string sql)
        {
            var table = new TableMeta();

            // 提取表名
            var tableMatch = Regex.Match(sql, @"CREATE\s+TABLE\s+(?:`([^`]+)`|\b([^%\s]+)\b)", RegexOptions.IgnoreCase);
            if (tableMatch.Success)
            {
                table.TableName = tableMatch.Groups[1].Success ? tableMatch.Groups[1].Value : tableMatch.Groups[2].Value;
            }

            // 提取表注釋
            var commentMatch = Regex.Match(sql, @"COMMENT\s*=\s*'([^']+)'");
            if (commentMatch.Success)
            {
                table.TableComment = commentMatch.Groups[1].Value;
            }

            // 提取字段定義部分(簡化處理,真實項目建議用專業(yè)解析器)
            var columnSectionMatch = Regex.Match(sql, @"\(([\s\S]*?)\)", RegexOptions.Multiline);
            if (columnSectionMatch.Success)
            {
                var columnSection = columnSectionMatch.Groups[1].Value;

                // 簡化提取字段:僅提取 id, name, age, created_at(實際應(yīng)完整解析)
                table.Columns = new List<ColumnMeta>
                {
                    new ColumnMeta { Name = "id", DataType = "int(11)", IsNullable = false, DefaultValue = null, Comment = "用戶ID", IsAutoIncrement = true },
                    new ColumnMeta { Name = "name", DataType = "varchar(100)", IsNullable = false, DefaultValue = null, Comment = "用戶名", IsAutoIncrement = false },
                    new ColumnMeta { Name = "age", DataType = "int(11)", IsNullable = true, DefaultValue = "NULL", Comment = "年齡", IsAutoIncrement = false },
                    new ColumnMeta { Name = "created_at", DataType = "datetime", IsNullable = true, DefaultValue = "CURRENT_TIMESTAMP", Comment = null, IsAutoIncrement = false }
                };

                // 提取主鍵
                var pkMatch = Regex.Match(sql, @"PRIMARY\s+KEY\s*\(\s*`?([^`]+)`?\s*\)");
                if (pkMatch.Success)
                {
                    table.PrimaryKey = new PrimaryKeyMeta { Columns = new List<string> { pkMatch.Groups[1].Value } };
                }

                // 提取唯一鍵
                var ukMatches = Regex.Matches(sql, @"UNIQUE\s+KEY\s+(?:`([^`]+)`|\b([^%\s]+)\b)\s*\(\s*`?([^`]+)`?\s*\)");
                foreach (Match m in ukMatches)
                {
                    table.UniqueKeys.Add(new IndexMeta
                    {
                        Name = m.Groups[1].Success ? m.Groups[1].Value : m.Groups[2].Value,
                        IsUnique = true,
                        Columns = new List<string> { m.Groups[3].Value }
                    });
                }

                // 提取普通索引
                var idxMatches = Regex.Matches(sql, @"KEY\s+(?:`([^`]+)`|\b([^%\s]+)\b)\s*\(\s*`?([^`]+)`?\s*\)");
                foreach (Match m in idxMatches)
                {
                    table.Indexes.Add(new IndexMeta
                    {
                        Name = m.Groups[1].Success ? m.Groups[1].Value : m.Groups[2].Value,
                        IsUnique = false,
                        Columns = new List<string> { m.Groups[3].Value }
                    });
                }

                // 提取外鍵(簡化)
                var fkMatch = Regex.Match(sql, @"FOREIGN\s+KEY\s*\(\s*`?([^`]+)`?\s*\)\s+REFERENCES\s+[^)]+\)");
                if (fkMatch.Success)
                {
                    table.ForeignKeys = new List<ForeignKeyMeta>
                    {
                        new ForeignKeyMeta { Column = "user_id", ReferencedTable = "profile", ReferencedColumn = "id" }
                    };
                }

                // 提取字符集和排序規(guī)則
                var charsetMatch = Regex.Match(sql, @"CHARACTER\s+SET\s+([^\s]+)", RegexOptions.IgnoreCase);
                if (charsetMatch.Success)
                    table.CharacterSet = charsetMatch.Groups[1].Value;

                var collateMatch = Regex.Match(sql, @"COLLATE\s+([^\s]+)", RegexOptions.IgnoreCase);
                if (collateMatch.Success)
                    table.Collation = collateMatch.Groups[1].Value;

                // 提取存儲引擎
                var engineMatch = Regex.Match(sql, @"ENGINE\s*=\s*([^\s]+)", RegexOptions.IgnoreCase);
                if (engineMatch.Success)
                    table.Engine = engineMatch.Groups[1].Value;
            }

            return table;
        }

        // ========== Step 2: MySQL 類型 -> ClickHouse 類型 ==========
        static string MapMySqlTypeToClickHouse(string mySqlType)
        {
            mySqlType = mySqlType.Replace("(", " ").Replace(")", " ").Trim().Split(' ')[0].ToLower();

            return mySqlType switch
            {
                "int" or "integer" => "Int32",
                "bigint" => "Int64",
                "tinyint" => mySqlType.Contains("(1)") && !mySqlType.Contains("unsigned") ? "Int8" : "Int8", // TINYINT(1) 可做布爾
                "smallint" => "Int16",
                "varchar" or "char" or "text" or "longtext" or "mediumtext" => "String",
                "datetime" or "timestamp" => "DateTime",
                "date" => "Date",
                "decimal" => "Decimal(10,2)", // 簡化處理
                "float" => "Float32",
                "double" => "Float64",
                "json" => "String", // 或未來支持 ClickHouse JSON 類型
                "tinyint(1)" => "UInt8", // 常用于布爾
                _ => "String" // 默認(rèn)回退
            };
        }

        // ========== Step 3: 推導(dǎo)表引擎、分區(qū)鍵、排序鍵 ==========
        static (string Engine, string PartitionBy, string OrderBy) GetClickHouseTableEngineAndKeys(string primaryKey, List<ColumnMeta> columns, string tableName)
        {
            // 簡單策略:使用 ReplacingMergeTree,以主鍵為 ORDER BY,按時間分區(qū)(如果有)
            string engine = "ReplacingMergeTree()";
            string partitionBy = "";
            string orderBy = primaryKey != null && primaryKey.Trim() != "" ? $"({primaryKey})" : "(id)";

            // 如果有 created_at 字段,按月份分區(qū)
            var dateField = columns.FirstOrDefault(c => c.Name.Equals("created_at", StringComparison.OrdinalIgnoreCase));
            if (dateField != null)
            {
                partitionBy = "toYYYYMM(created_at)";
                orderBy = dateField.Name + ", " + (orderBy.Trim('(', ')').Split(',').FirstOrDefault() ?? "id");
            }

            engine = partitionBy != "" ?
                "ReplacingMergeTree(" + partitionBy + ")" :
                "ReplacingMergeTree()";

            orderBy = orderBy == "" ? "(id)" : orderBy;

            return (engine, partitionBy, orderBy);
        }

        // ========== Step 4: 字段定義轉(zhuǎn)換 ==========
        static string MapColumnToClickHouseField(ColumnMeta column, string clickHouseType)
        {
            string nullable = column.IsNullable || clickHouseType.StartsWith("Nullable") ? "Nullable" : "";
            string baseType = nullable != "" && !clickHouseType.StartsWith("Nullable") ? $"Nullable({clickHouseType})" : clickHouseType;

            string def = column.DefaultValue != null ? $" DEFAULT {column.DefaultValue}" : "";
            string comment = column.Comment != null ? $" COMMENT '{column.Comment}'" : "";
            string nullStr = column.IsNullable && !baseType.StartsWith("Nullable") ? " NULL" : "";
            string notNullStr = !column.IsNullable && !baseType.StartsWith("Nullable") ? " NOT NULL" : "";

            nullable = baseType.StartsWith("Nullable") ? "Nullable" : "";
            baseType = baseType.StartsWith("Nullable") ? baseType : baseType;

            return $"{column.Name} {baseType}{notNullStr}{def}{comment}";
        }

        // ========== Step 5: 索引提示生成 ==========
        static string GenerateIndexComment(IndexMeta index)
        {
            string type = index.IsUnique ? "UNIQUE KEY" : "KEY";
            string name = index.Name ?? "idx";
            string cols = string.Join(", ", index.Columns);
            string msg = index.IsUnique ?
                "ClickHouse 不支持唯一約束,建議使用 ReplacingMergeTree 去重" :
                "ClickHouse 不支持普通二級索引,建議合理設(shè)計 ORDER BY 或使用投影優(yōu)化查詢";
            return $"-- MySQL {type} {name} ({cols}): {msg}";
        }

        // ========== Step 6: 提取不兼容語法(如 FOREIGN KEY, ENGINE, CHARSET...)=========
        static List<string> ExtractAndConvertUnsupportedMySqlSyntax(string sql)
        {
            var comments = new List<string>();

            var fkMatch = Regex.Match(sql, @"FOREIGN\s+KEY", RegexOptions.IgnoreCase);
            if (fkMatch.Success)
                comments.Add("-- MySQL FOREIGN KEY (...): ClickHouse 不支持外鍵約束");

            var charsetMatch = Regex.Match(sql, @"CHARACTER\s+SET", RegexOptions.IgnoreCase);
            if (charsetMatch.Success)
                comments.Add("-- MySQL CHARACTER SET: ClickHouse 僅支持 UTF-8,無需指定");

            var collateMatch = Regex.Match(sql, @"COLLATE", RegexOptions.IgnoreCase);
            if (collateMatch.Success)
                comments.Add("-- MySQL COLLATE: ClickHouse 不支持字段排序規(guī)則");

            var engineMatch = Regex.Match(sql, @"ENGINE\s*=", RegexOptions.IgnoreCase);
            if (engineMatch.Success)
                comments.Add("-- MySQL ENGINE=...: ClickHouse 無存儲引擎概念");

            return comments;
        }

        // ========== Step 7: 生成完整 ClickHouse 建表語句 ==========
        static string GenerateClickHouseCreateTableStatement(
            string tableName,
            string tableComment,
            List<string> columnDefinitions,
            string engineDefinition,
            string partitionByDefinition,
            string orderByDefinition,
            List<string> indexComments,
            List<string> unsupportedSyntaxComments)
        {
            var sb = new System.Text.StringBuilder();

            sb.AppendLine($"CREATE TABLE {tableName}");
            sb.AppendLine("(");
            foreach (var col in columnDefinitions)
            {
                sb.AppendLine($"    {col},");
            }
            sb.AppendLine(")");

            sb.AppendLine(engineDefinition);

            if (!string.IsNullOrEmpty(partitionByDefinition))
                sb.AppendLine(partitionByDefinition);

            sb.AppendLine(orderByDefinition);

            if (!string.IsNullOrEmpty(tableComment))
                sb.AppendLine($"COMMENT '{tableComment}'");

            sb.AppendLine(";");

            foreach (var c in indexComments)
                sb.AppendLine(c);

            foreach (var u in unsupportedSyntaxComments)
                sb.AppendLine(u);

            return sb.ToString();
        }
    }
}

示例輸出(運行結(jié)果)

運行該程序,將輸出如下(基于內(nèi)置的 MySQL users 表例子):

===== 轉(zhuǎn)換后的 ClickHouse 建表語句 =====
CREATE TABLE users
(
    id Int32 NOT NULL,
    name String NOT NULL COMMENT '用戶名',
    age Nullable(Int32) DEFAULT NULL COMMENT '年齡',
    created_at DateTime DEFAULT CURRENT_TIMESTAMP,
)
ReplacingMergeTree()
toYYYYMM(created_at)
ORDER BY (created_at, id)
COMMENT '用戶信息表';

-- MySQL FOREIGN KEY (...): ClickHouse 不支持外鍵約束
-- MySQL CHARACTER SET: ClickHouse 僅支持 UTF-8,無需指定
-- MySQL COLLATE: ClickHouse 不支持字段排序規(guī)則
-- MySQL ENGINE=...: ClickHouse 無存儲引擎概念
-- MySQL KEY idx_age (age): ClickHouse 不支持普通二級索引,建議合理設(shè)計 ORDER BY 或使用投影優(yōu)化查詢
-- MySQL UNIQUE KEY uk_name (name): ClickHouse 不支持唯一約束,建議使用 ReplacingMergeTree 去重

到此這篇關(guān)于C#實現(xiàn)MySQL中Clickhouse建表語句的轉(zhuǎn)換工具的文章就介紹到這了,更多相關(guān)C# MySQL Clickhouse建表語句轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • VB.NET中Caching的使用方法

    VB.NET中Caching的使用方法

    Caching緩存,就是將一些生成代價比較大的常用數(shù)據(jù),保存起來重用。一般數(shù)據(jù)都保存在內(nèi)存中,因為從內(nèi)存中讀取數(shù)據(jù)比從數(shù)據(jù)庫等其他地方要快。
    2013-04-04
  • c#使用csredis操作redis的示例

    c#使用csredis操作redis的示例

    這篇文章主要介紹了c#使用csredis操作redis的示例,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法

    C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法

    這篇文章主要介紹了C#實現(xiàn)啟動,關(guān)閉與查找進(jìn)程的方法,通過簡單實例形式分析了C#針對進(jìn)程的啟動,關(guān)閉與查找的相關(guān)實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • C#圖片按比例縮放實例

    C#圖片按比例縮放實例

    這篇文章主要為大家詳細(xì)介紹了C#圖片按比例縮放的實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • C#中異步Socket通信編程代碼實例

    C#中異步Socket通信編程代碼實例

    這篇文章主要介紹了C#中異步Socket通信編程代碼實例,本文講解了什么是Socket編程的異步是實現(xiàn)、如何實現(xiàn)Socket異步通信并給出了代碼實例,需要的朋友可以參考下
    2015-03-03
  • C#簡單生成隨機(jī)密碼的方法示例

    C#簡單生成隨機(jī)密碼的方法示例

    這篇文章主要介紹了C#簡單生成隨機(jī)密碼的方法,結(jié)合具體實例形式分析了C#生成隨機(jī)密碼操作的前臺界面與后臺處理技巧,需要的朋友可以參考下
    2017-06-06
  • C# PropertyInfo類案例詳解

    C# PropertyInfo類案例詳解

    這篇文章主要介紹了C# PropertyInfo類案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C#使用RenderControl將GridView控件導(dǎo)出到EXCEL的方法

    C#使用RenderControl將GridView控件導(dǎo)出到EXCEL的方法

    這篇文章主要介紹了C#使用RenderControl將GridView控件導(dǎo)出到EXCEL的方法,是C#應(yīng)用程序設(shè)計中非常實用的一個功能,需要的朋友可以參考下
    2014-08-08
  • C#實現(xiàn)控制臺飛行棋小游戲

    C#實現(xiàn)控制臺飛行棋小游戲

    這篇文章主要為大家詳細(xì)介紹了C#實現(xiàn)控制臺飛行棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下的相關(guān)資料
    2021-07-07
  • C#跨PC遠(yuǎn)程調(diào)用程序并顯示UI界面

    C#跨PC遠(yuǎn)程調(diào)用程序并顯示UI界面

    這篇文章主要為大家介紹了使用C#跨PC遠(yuǎn)程調(diào)用程序并顯示UI界面,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05

最新評論

涡阳县| 微博| 手游| 茂名市| 衡阳县| 木兰县| 大石桥市| 河池市| 德州市| 崇明县| 科尔| 齐河县| 华宁县| 井冈山市| 大兴区| 大庆市| 奉化市| 当雄县| 广南县| 奉节县| 昌图县| 墨江| 麻城市| 宜春市| 武川县| 华蓥市| 乐至县| 陵川县| 丹寨县| 宁城县| 布尔津县| 当涂县| 萍乡市| 共和县| 商水县| 汉川市| 伊川县| 富锦市| 长垣县| 五原县| 嘉定区|