sql-serverdockersqlcmdazure-sql-edge

Initialize SQL Server database in docker container without sqlcmd


I am working on a MacBook Pro with M1 CPU so I can't use the "normal" mssql docker image. I am using azure-sql-edge that doesn't have sqlcmd to initialize the database (create schema, database, login).

I have created a sql script that I would like to run once the container starts but I can't find any alternative to sqlcmd.

Is there any other way to do it?


Solution

  • Since I am starting a new project I looked into this issue again and found a good solution for me.

    I found go-sqlcmd, a new implementation of sqlcmd using golang and it's compatible with M1 chips.

    So I am running azure-sql-edge as before using docker compose:

    version: "3.9"
    
    services:
      mssql:
        image: mcr.microsoft.com/azure-sql-edge:latest
        command: /opt/mssql/bin/sqlservr
        environment:
          ACCEPT_EULA: "Y"
          SA_PASSWORD: ${DATABASE_SA_PASSWORD}
        stdin_open: true
        ports:
          - 1433:1433
    

    When the database container is up and in idle I run this bash script (in my case I am reading the environmnet variables from a .NET appsettings.json file):

    cat <appsetting.json> | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' > temp
    
    # Show env vars
    grep -v '^#' temp
    
    # Export env vars
    export $(grep -v '^#' temp | xargs)
    
    export SQLCMDPASSWORD=$DATABASE_SA_PASSWORD
    
    sqlcmd -U sa \
        -v DATABASE_SCHEMA=$DATABASE_SCHEMA \
        -v DATABASE_DB_NAME=$DATABASE_DB_NAME \
        -v DATABASE_LOGIN_NAME=$DATABASE_LOGIN_NAME \
        -v DATABASE_LOGIN_PASSWORD=$DATABASE_LOGIN_PASSWORD \
        -i sql/init-db.sql,sql/init-user.sql
    

    I had to split the database and schema creation in a script, then I create the user and assign it to the database.

    The sql scripts, init-db.sql:

    USE master
    
    IF NOT EXISTS (SELECT name FROM sys.schemas WHERE name = N'$(DATABASE_SCHEMA)')
    BEGIN
        EXEC sys.sp_executesql N'CREATE SCHEMA [$(DATABASE_SCHEMA)] AUTHORIZATION [dbo]'
    END
    
    IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'$(DATABASE_DB_NAME)')
    BEGIN
        CREATE DATABASE $(DATABASE_DB_NAME)
    END
    

    init-user.sql:

    USE $(DATABASE_DB_NAME)
    
    IF NOT EXISTS(SELECT principal_id FROM sys.server_principals WHERE name = '$(DATABASE_LOGIN_NAME)') BEGIN
        CREATE LOGIN $(DATABASE_LOGIN_NAME) 
        WITH PASSWORD = '$(DATABASE_LOGIN_PASSWORD)'
    END
    
    IF NOT EXISTS(SELECT principal_id FROM sys.database_principals WHERE name = '$(DATABASE_LOGIN_NAME)') BEGIN
        CREATE USER $(DATABASE_LOGIN_NAME) FOR LOGIN $(DATABASE_LOGIN_NAME)
    END