JSON数据一键导入SQL Server

复制代码
import json
import pyodbc
import os
from datetime import datetime


class JSONToSQLServerImporter:

    def __init__(self):
        self.json_file_path = r"C:\sample.json"
        self.connection_string = None
        self.db_connection = None

    def set_connection_string(self, server, database, username, password):
        self.connection_string = f'DRIVER={{SQL Server}};SERVER={server};DATABASE={database};UID={username};PWD={password}'

    def connect_to_database(self):
        try:
            self.db_connection = pyodbc.connect(self.connection_string)
            print("成功连接到数据库")
            return True
        except pyodbc.Error as e:
            print(f"数据库连接失败: {e}")
            return False

    def read_json_file(self, file_path=None):
        """读取JSON文件数据"""
        try:
            # 使用指定路径或默认路径
            current_path = file_path if file_path else self.json_file_path

            if not os.path.exists(current_path):
                print(f"❌ JSON文件不存在: {current_path}")
                print(f"📁 请将您的JSON文件放在以下位置之一:")
                print(f"   - Windows: C:\\sample.json")
                print(f"   - Mac/Linux: ~/sample.json")
                print(f"   - 或者在运行时指定文件路径")

                # 尝试查找当前目录下的JSON文件
                current_dir_files = [f for f in os.listdir('.') if f.endswith('.json')]
                if current_dir_files:
                    print(f"\n🔍 在当前目录找到JSON文件:")
                    for i, json_file in enumerate(current_dir_files, 1):
                        print(f"   {i}. {json_file}")
                    print(f"\n💡 提示: 您可以复制其中一个文件到指定位置,或者使用命令行参数指定文件")

                return None

            with open(current_path, 'r', encoding='utf-8') as f:
                data = json.load(f)

            print(f"✅ 成功读取JSON文件: {current_path}")
            print(f"📊 共 {len(data) if isinstance(data, list) else 1} 条记录")
            return data

        except json.JSONDecodeError as e:
            print(f"❌ JSON文件格式错误: {e}")
            print(f"💡 提示: 请检查JSON格式是否正确,可以使用在线JSON验证工具")
            return None
        except PermissionError:
            print(f"❌ 没有权限读取文件: {current_path}")
            print(f"💡 提示: 请检查文件权限或使用管理员权限运行")
            return None
        except Exception as e:
            print(f"❌ 读取JSON文件时发生错误: {e}")
            return None

    def create_table_if_not_exists(self, table_name, sample_data):
        try:
            cursor = self.db_connection.cursor()

            cursor.execute(f"IF OBJECT_ID('{table_name}', 'U') IS NOT NULL SELECT 1 ELSE SELECT 0")
            table_exists = cursor.fetchone()[0]

            if table_exists:
                print(f"表 {table_name} 已存在")
                return True

            columns = []
            if isinstance(sample_data, dict):
                for key, value in sample_data.items():
                    data_type = self._get_sql_data_type(value)
                    columns.append(f"[{key}] {data_type}")
            else:
                print("无法确定数据结构,需要字典类型的示例数据")
                return False

            columns_str = ", ".join(columns)
            create_table_sql = f"CREATE TABLE {table_name} ({columns_str})"

            cursor.execute(create_table_sql)
            self.db_connection.commit()
            print(f"成功创建表 {table_name}")
            return True

        except Exception as e:
            print(f"创建表时发生错误: {e}")
            self.db_connection.rollback()
            return False

    def _get_sql_data_type(self, value):
        if isinstance(value, int):
            return "INT"
        elif isinstance(value, float):
            return "FLOAT"
        elif isinstance(value, str):
            if self._is_datetime_string(value):
                return "DATETIME"
            return "NVARCHAR(MAX)"
        elif isinstance(value, bool):
            return "BIT"
        elif isinstance(value, (list, dict)):
            return "NVARCHAR(MAX)"
        elif value is None:
            return "NVARCHAR(MAX)"
        else:
            return "NVARCHAR(MAX)"

    def _is_datetime_string(self, value):
        if not isinstance(value, str):
            return False

        datetime_formats = [
            "%Y-%m-%d %H:%M:%S",
            "%Y-%m-%d",
            "%Y/%m/%d %H:%M:%S",
            "%Y/%m/%d",
            "%d/%m/%Y",
            "%d-%m-%Y"
        ]

        for fmt in datetime_formats:
            try:
                datetime.strptime(value, fmt)
                return True
            except ValueError:
                continue

        return False

    def insert_data(self, table_name, data):
        try:
            cursor = self.db_connection.cursor()

            if isinstance(data, list):
                total_records = len(data)
                success_count = 0

                for index, record in enumerate(data):
                    if self._insert_single_record(cursor, table_name, record):
                        success_count += 1

                    if (index + 1) % 10 == 0 or index + 1 == total_records:
                        print(f"进度: {index + 1}/{total_records} 条记录")

                self.db_connection.commit()
                print(f"数据插入完成,成功: {success_count}/{total_records} 条")

            elif isinstance(data, dict):
                if self._insert_single_record(cursor, table_name, data):
                    self.db_connection.commit()
                    print("单条记录插入成功")
                else:
                    self.db_connection.rollback()
            else:
                print(f"不支持的数据格式: {type(data)}")

        except Exception as e:
            print(f"插入数据时发生错误: {e}")
            self.db_connection.rollback()

    def _insert_single_record(self, cursor, table_name, record):
        try:
            if not isinstance(record, dict):
                return False

            columns = list(record.keys())
            values = list(record.values())

            for i in range(len(values)):
                if isinstance(values[i], (list, dict)):
                    values[i] = json.dumps(values[i], ensure_ascii=False)
                elif values[i] is None:
                    values[i] = None

            placeholders = ",".join(["?"] * len(values))
            columns_str = ",".join([f"[{col}]" for col in columns])

            sql = f"INSERT INTO {table_name} ({columns_str}) VALUES ({placeholders})"

            cursor.execute(sql, values)
            return True

        except Exception as e:
            print(f"插入单条记录时发生错误: {e}")
            return False

    def close_connection(self):
        if self.db_connection:
            self.db_connection.close()
            print("数据库连接已关闭")

    def run_import(self, server, database, username, password, table_name="json_data", json_file_path=None):
        """运行完整的导入流程"""
        try:
            print("\n🚀 开始JSON数据导入流程...")
            print("-" * 60)

            self.set_connection_string(server, database, username, password)

            if not self.connect_to_database():
                return False

            # 使用指定的JSON文件路径或默认路径
            data = self.read_json_file(json_file_path)
            if data is None:
                return False

            sample_data = data[0] if isinstance(data, list) else data
            if not self.create_table_if_not_exists(table_name, sample_data):
                return False

            self.insert_data(table_name, data)

            print("JSON数据导入完成!")
            return True

        except Exception as e:
            print(f"导入过程中发生未预期的错误: {e}")
            return False
        finally:
            self.close_connection()


def main():
    """主函数"""
    print("🚀 JSON到SQL Server数据导入工具")
    print("=" * 60)

    # 解析命令行参数
    import sys
    json_file_path = None
    if len(sys.argv) > 1:
        json_file_path = sys.argv[1]
        print(f"📄 使用命令行指定的JSON文件: {json_file_path}")

    importer = JSONToSQLServerImporter()

    # 如果没有通过命令行指定文件,询问用户
    if not json_file_path:
        use_default = input("是否使用默认JSON文件路径?(y/n,默认y): ").lower()
        if use_default != 'n':
            print(f"📁 默认JSON文件路径: {importer.json_file_path}")
        else:
            json_file_path = input("请输入JSON文件的完整路径: ").strip()
            if not json_file_path:
                print("⚠️  未指定文件路径,将使用默认路径")

    print()
    server = input("请输入SQL Server服务器地址: ")
    database = input("请输入数据库名称: ")
    username = input("请输入用户名: ")
    password = input("请输入密码: ")
    table_name = input("请输入表名 (默认为 json_data): ") or "json_data"

    print("\n开始导入操作...")
    print("=" * 50)

    success = importer.run_import(server, database, username, password, table_name, json_file_path)

    if success:
        print("\n数据导入成功!")
    else:
        print("\n数据导入失败,请检查错误信息。")


if __name__ == "__main__":
    main()
相关推荐
一分半心动2 小时前
清理C盘的python脚本
开发语言·python
AI手记叨叨3 小时前
Python数学:几何运算
python·数学·解析几何·射影几何·微分几何·欧几里得几何
toolhow3 小时前
SelfAttenion自注意力机制
pytorch·python·深度学习
智航GIS3 小时前
6.2 while循环
java·前端·python
qq_336313933 小时前
java基础-IO流(转换流)
java·开发语言·python
Stestack3 小时前
ssh批量机器免密操作
linux·python·ssh
a程序小傲3 小时前
得物Java面试被问:反射机制的原理和应用场景
java·python·面试
于越海3 小时前
学习小项目:用 Python 自动统计编程课绩点(5.0 制|百分制直算|重修取最高)
开发语言·笔记·python·学习·学习方法
xingzhemengyou13 小时前
Python GUI中常用的after
开发语言·python