Программная вставка строк, где значение поля является оператором SQL - PullRequest
2 голосов
/ 28 марта 2012

В настоящее время я работаю над решением на C # для копирования таблиц базы данных из Oracle в PostgreSQL. Все отлично работает, кроме одной вещи. Когда я копирую одну из моих таблиц, которая содержит операторы sql в одном из своих полей, она падает из-за наличия двух одинарных кавычек. Операторы SQL ДОЛЖНЫ оставаться в таблице, так как они используются, чтобы сделать независимую базу данных программы.

Есть ли способ написать следующий SQL, но без двух одинарных кавычек, показанных рядом со значением «ИСТИНА» в конце строки. Я также включил свой код ниже, чтобы показать, как инструкция построена в C #. Это столбец varchar2 в Oracle и столбец TEXT в PostgreSQL.

РЕДАКТИРОВАТЬ: Показанный пример sql является действительным оператором INSERT, сгенерированным моим кодом C #, который затем будет запущен в базе данных postgresql для добавления записи в таблицу. Он будет использоваться для вставки, среди прочего, текстового поля, содержащего оператор sql в виде строки.

INSERT INTO SQL_FACTORY_TEST (SQL_FACTORY_TEST_ID,SQL_FACTORY_DIALECT,SQL_FACTORY_QUERY_NAME,SQL_FACTORY_SQL_COMMAND,USER_NAME) 
VALUES (21, 'ORACLE', 'GET_CLUSTERS', 'SELECT CLUSTER_ID, NUM_POINTS, FEATURE_PK, A.CELL_CENTROID.SDO_POINT.X, A.CELL_CENTROID.SDO_POINT.Y, A.CLUSTER_CENTROID.SDO_POINT.X, A.CLUSTER_CENTROID.SDO_POINT.Y, TO_CHAR (A.CLUSTER_EXTENT.GET_WKT ()),  TO_CHAR (A.CELL_GEOM.GET_WKT ()), A.CLUSTER_EXTENT.SDO_SRID FROM (SELECT CLUSTER_ID, NUM_POINTS, FEATURE_PK, SDO_CS.transform (CLUSTER_CENTROID, 4326) cluster_centroid, CLUSTER_EXTENT, SDO_CS.transform (CELL_CENTROID, 4326) cell_centroid, CELL_GEOM FROM :0) a  where sdo_filter( A.CELL_GEOM, SDO_CS.transform(mdsys.sdo_geometry(2003, :1, NULL, mdsys.sdo_elem_info_array(1,1003,3),mdsys.sdo_ordinate_array(:2, :3, :4, :5)),81989)) = 'TRUE'', 'PUBLIC')

Пример кода:

oleDataBaseConnection.OleExecutePureSqlQuery("SELECT * FROM " + tableName);

    if (oleDataBaseConnection.HasRows())
    {
        while (oleDataBaseConnection.NextRecord())
        {
            Dictionary<string, string> postgreSQLQueries = TypeConversion.GetQueryDictionary("POSTGRESQL");

            string postgreSQLInsertQuery;

            postgreSQLQueries.TryGetValue("INSERT", out postgreSQLInsertQuery);

            postgreSQLInsertQuery = postgreSQLInsertQuery.Replace("{0}", tableName);

            StringBuilder postgresQuery = new StringBuilder();

            postgresQuery.Append(postgreSQLInsertQuery);

            postgresQuery.Append("(");

            int columnCounter = 0;

            //add a column parameter to query for each of our columns
            foreach (KeyValuePair<string, string> t in columnData)
            {
                postgresQuery.Append(t.Key + ",");
                columnCounter++;
            }

            postgresQuery = postgresQuery.Remove(postgresQuery.Length - 1, 1);
            postgresQuery.Append(") ");

            postgresQuery.Append("VALUES (");

            //Loop through values and 

            for (int i = 0; i < columnCounter; i++)
            {
                string[] foo = new string[columnData.Count];
                columnData.Values.CopyTo(foo, 0);

                if (foo[i].ToUpper() == "TEXT")
                {
                    postgresQuery.Append("'" + oleDataBaseConnection.GetFieldById(i) + "', ");
                }
                else
                {
                    postgresQuery.Append(oleDataBaseConnection.GetFieldById(i) + ", ");
                }
            }

            postgresQuery = postgresQuery.Remove(postgresQuery.Length - 2, 2);
            postgresQuery.Append(") ");
            postgresSQLDBConnection.PostgreSQLExecutePureSqlNonQuery(postgresQuery.ToString());
        }
    }

Ответы [ 3 ]

1 голос
/ 28 марта 2012

Я думаю, что лучший подход - использовать параметризованный запрос вставки. так что вы на самом деле строите запрос как:

INSERT INTO [Table] VALUES (@Column1, @Column2, @Column3)

затем передавая переменную в запрос. Что-то вроде:

List<OleDbParameter> parameters = new List<OleDbParameter>();
            for (int i = 0; i < columnCounter; i++)
            {
                postgresQuery.Append(string.Format("@Column{0}, ", i));
                parameters.Add(new OleDbParameter(string.Format("@Column{0}, ", i), oleDataBaseConnection.GetFieldById(i));
            }

Затем передайте paremeters.ToArray() вам OleDbCommand при выполнении. Это означает, что c # сделает все экранирование и определит тип данных для вас. Возможно, потребуется немного доработать, чтобы удовлетворить ваши потребности, но суть в этом есть.

1 голос
/ 28 марта 2012

Лучшее решение - использовать PreparedStatement, где вы не передаете литералы напрямую. Я не знаю C #, поэтому я не могу дать вам пример для этого.

Однако, если у вас есть , чтобы сохранить это утверждение, вы можете использовать строковый литерал " доллара в кавычках " в PostgreSQL.

INSERT INTO SQL_FACTORY_TEST (SQL_FACTORY_TEST_ID,SQL_FACTORY_DIALECT,SQL_FACTORY_QUERY_NAME,SQL_FACTORY_SQL_COMMAND,USER_NAME) 
VALUES (21, 'ORACLE', 'GET_CLUSTERS', $$ ...... 'TRUE'$$, 'PUBLIC')

$$ заменяет одинарные кавычки вокруг литерала. Если есть вероятность, что ваше значение содержит $$, вы также можете добавить к нему уникальный идентификатор, например,

$42$String with embedded single quotes ''' and two $$ dollar characters$42$
0 голосов
/ 28 марта 2012

Вы всегда должны правильно экранировать и удалять значения, хранящиеся в базе данных.

Клиентская библиотека PostgreSQL предоставляет для этой цели функцию PQescapeLiteral .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...