Search code examples
sqliteactionscript-3air

SQLite Insert Looping from Excel File to SQLite Database


First of all, I am new to SQLite.

I try to make an AIR application that can import value from excel file into SQLite database. What I try do to is to make a loop that allow me to insert data from excel into SQLite database. Below is my code;

package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.SQLEvent;
    import flash.events.TimerEvent;
    import flash.data.SQLStatement;
    import flash.data.SQLConnection;
    import flash.utils.Timer;
    import flash.filesystem.File;
    import flash.net.FileFilter;
    import fl.controls.Button;
    import fl.controls.DataGrid;
    import fl.controls.ScrollPolicy;
    import lib.xlsxreader.Worksheet;
    import lib.xlsxreader.XLSXLoader;

    public class DataTransfer extends MovieClip
    {
        private var i;
        private var fileGet: File = new File();
        private var dbFile: File = new File();
        private var excel_loader: XLSXLoader = new XLSXLoader();

        private var sqlc: SQLConnection = new SQLConnection();
        private var sqls: SQLStatement = new SQLStatement();

        public function DataTransfer()
        {
            var btnImport: Button = new Button();

            btnImport.x = btnImport.y = 10;
            btnImport.label = "Select Excel File";
            btnImport.addEventListener(MouseEvent.CLICK, selectExcelFile);
            addChild(btnImport);

            fileGet = File.applicationDirectory;
            fileGet.addEventListener(Event.CANCEL, fileCancel);
            fileGet.addEventListener(Event.SELECT, fileSelect);
            dbFile = fileGet.resolvePath("test.sqlite");

            excel_loader.addEventListener(Event.COMPLETE, loadingComplete);

            sqlc.addEventListener(SQLEvent.OPEN, db_opened);
            sqlc.openAsync(dbFile);
        }

        private function selectExcelFile(e: MouseEvent): void
        {
            var fileFilter = new FileFilter("Select Excel File", "*.xls;*.xlsx;*.xlsm");

            fileGet.browseForOpen("Select Excel File", [fileFilter]);
        }

        private function fileCancel(e: Event): void
        {
            trace("Cancel");
        }

        private function fileSelect(e: Event): void
        {
            trace("File Path is : " + fileGet.nativePath);
            excel_loader.load(fileGet.nativePath);
        }

        private function loadingComplete(e: Event): void
        {
            var row: int = new int();
            var sheet_2: Worksheet = excel_loader.worksheet("Sheet2");
            var arColumn1: Array = new Array();
            var arColumn2: Array = new Array();
            var arColumn3: Array = new Array();

            row = sheet_2.rows;

            sqls.text = ""

            for (i = 1; i <= row; i++)
            {
                arColumn1[i - 1] = sheet_2.getCellValue("A" + i);
                arColumn2[i - 1] = sheet_2.getCellValue("B" + i);
                arColumn3[i - 1] = sheet_2.getCellValue("C" + i);

                sqls.text = sqls.text + "INSERT INTO test_table (col1) VALUES('" + arColumn1[i - 1] + "');";
            }

            trace(sqls.text);
            sqls.execute();
            refresh();

            var dtExcel: DataGrid = new DataGrid();

            dtExcel.x = 10;
            dtExcel.y = 40;
            dtExcel.width = 300;
            dtExcel.height = 100;
            dtExcel.horizontalScrollPolicy = ScrollPolicy.ON;
            dtExcel.verticalScrollPolicy = ScrollPolicy.ON;

            var col1 = dtExcel.addColumn("Column1");
            var col2 = dtExcel.addColumn("Column2");
            var col3 = dtExcel.addColumn("Column3");

            col1.minWidth = 100;
            col2.minWidth = 200;
            col3.minWidth = 300;

            for (i = 0; i <= row - 1; i++)
            {
                dtExcel.addItem(
                {
                    Column1: arColumn1[i],
                    Column2: arColumn2[i],
                    Column3: arColumn3[i]
                });
            }

            addChild(dtExcel);
        }

        private function db_opened(e: SQLEvent): void
        {
            sqls.sqlConnection = sqlc;
            sqls.text = "CREATE TABLE IF NOT EXISTS test_table (id INTEGER PRIMARY KEY AUTOINCREMENT, col1 TEXT, col2 TEXT, col3 TEXT)";
            sqls.execute();
            refresh();
        }

        private function refresh(e: TimerEvent = null): void
        {
            var timer: Timer = new Timer(10, 1);
            timer.addEventListener(TimerEvent.TIMER, refresh);

            if (!sqls.executing)
            {
                sqls.text = "SELECT * FROM test_table";
                sqls.execute();
            }
            else
            {
                timer.start();
            }
        }
    }
}

I have problem at this line;

for (i = 1; i <= row; i++)
{
    arColumn1[i - 1] = sheet_2.getCellValue("A" + i);
    arColumn2[i - 1] = sheet_2.getCellValue("B" + i);
    arColumn3[i - 1] = sheet_2.getCellValue("C" + i);

    sqls.text = sqls.text + "INSERT INTO test_table (col1) VALUES('" + arColumn1[i - 1] + "');";
}

I try to loop the sqls.text so that the excel value can be pass into the SQLite database. However sqls.execute() only execute the first INSERT.

I try to see the value of sqls.text using trace(sqls.text) and I think my SQL statement is correct (assuming that SQLite do use PostgreSQL syntax) as shown below;

INSERT INTO test_table (col1) VALUES('saya');INSERT INTO test_table (col1) VALUES('makan');INSERT INTO test_table (col1) VALUES('minum');INSERT INTO test_table (col1) VALUES('');INSERT INTO test_table (col1) VALUES('');INSERT INTO test_table (col1) VALUES('main');

I assume my syntax is correct as I use the above syntax in https://rextester.com/l/postgresql_online_compiler and it work just fine.

I assume my looping implementation is correct because my datagrid dtExcel show the exact correct value in correct column and row.

I also try to use sqls.execute() in the loop but I get the following error:

Error: Error #3106: Property cannot be changed while SQLStatement.executing is true.

Is there are way to do this loop? Or I need to use open source AS3 SQLite library to do this?

Edit:

According to here, I can change the above SQLite syntax into;

INSERT INTO test_table (col1) VALUES('saya'),('makan'),('minum'),(''),(''),('main');

However, this still give following error;

Error #2044: Unhandled SQLErrorEvent:. errorID=3115, operation=execute , message=Error #3115: SQL Error. , details=near ',': syntax error


Solution

  • Try to make one command per each loop together with execute and parameters in the prepared statement:

    for (i = 1; i <= row; i++)
    {
     arColumn1[i - 1] = sheet_2.getCellValue("A" + i);
     arColumn2[i - 1] = sheet_2.getCellValue("B" + i);
     arColumn3[i - 1] = sheet_2.getCellValue("C" + i);
    
     sqls.clearParameters();
     sqls.text = "INSERT INTO test_table (col1, col2, col3) VALUES(:param1, :param2, :param3)";
     sqls.parameters[":param1"] = arColumn1[i - 1];
     sqls.parameters[":param2"] = arColumn2[i - 1];
     sqls.parameters[":param3"] = arColumn3[i - 1];
     sqls.execute();
    }
    

    Also, you could use transaction:

    sqls.begin();
     - for loop here
    sqls.commit();