SQL Server xml строковый парсинг в varchar поле

Я на самом деле решил это сам в конце путем управления реестром. Я создал класс для содержания функциональности, содержание которой я включал здесь:

///<summary>
/// Class to assist with creation and removal of ODBC DSN entries
///</summary>
public static class ODBCManager
{
    private const string ODBC_INI_REG_PATH = "SOFTWARE\\ODBC\\ODBC.INI\\";
    private const string ODBCINST_INI_REG_PATH = "SOFTWARE\\ODBC\\ODBCINST.INI\\";

    /// <summary>
    /// Creates a new DSN entry with the specified values. If the DSN exists, the values are updated.
    /// </summary>
    /// <param name="dsnName">Name of the DSN for use by client applications</param>
    /// <param name="description">Description of the DSN that appears in the ODBC control panel applet</param>
    /// <param name="server">Network name or IP address of database server</param>
    /// <param name="driverName">Name of the driver to use</param>
    /// <param name="trustedConnection">True to use NT authentication, false to require applications to supply username/password in the connection string</param>
    /// <param name="database">Name of the datbase to connect to</param>
    public static void CreateDSN(string dsnName, string description, string server, string driverName, bool trustedConnection, string database)
    {
        // Lookup driver path from driver name
        var driverKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + driverName);
        if (driverKey == null) throw new Exception(string.Format("ODBC Registry key for driver '{0}' does not exist", driverName));
        string driverPath = driverKey.GetValue("Driver").ToString();

        // Add value to odbc data sources
        var datasourcesKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + "ODBC Data Sources");
        if (datasourcesKey == null) throw new Exception("ODBC Registry key for datasources does not exist");
        datasourcesKey.SetValue(dsnName, driverName);

        // Create new key in odbc.ini with dsn name and add values
        var dsnKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + dsnName);
        if (dsnKey == null) throw new Exception("ODBC Registry key for DSN was not created");
        dsnKey.SetValue("Database", database);
        dsnKey.SetValue("Description", description);
        dsnKey.SetValue("Driver", driverPath);
        dsnKey.SetValue("LastUser", Environment.UserName);
        dsnKey.SetValue("Server", server);
        dsnKey.SetValue("Database", database);
        dsnKey.SetValue("Trusted_Connection", trustedConnection ? "Yes" : "No");
    }

    /// <summary>
    /// Removes a DSN entry
    /// </summary>
    /// <param name="dsnName">Name of the DSN to remove.</param>
    public static void RemoveDSN(string dsnName)
    {
        // Remove DSN key
        Registry.LocalMachine.DeleteSubKeyTree(ODBC_INI_REG_PATH + dsnName);

        // Remove DSN name from values list in ODBC Data Sources key
        var datasourcesKey = Registry.LocalMachine.CreateSubKey(ODBC_INI_REG_PATH + "ODBC Data Sources");
        if (datasourcesKey == null) throw new Exception("ODBC Registry key for datasources does not exist");
        datasourcesKey.DeleteValue(dsnName);
    }

    ///<summary>
    /// Checks the registry to see if a DSN exists with the specified name
    ///</summary>
    ///<param name="dsnName"></param>
    ///<returns></returns>
    public static bool DSNExists(string dsnName)
    {
        var driversKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + "ODBC Drivers");
        if (driversKey == null) throw new Exception("ODBC Registry key for drivers does not exist");

        return driversKey.GetValue(dsnName) != null;
    }

    ///<summary>
    /// Returns an array of driver names installed on the system
    ///</summary>
    ///<returns></returns>
    public static string[] GetInstalledDrivers()
    {
        var driversKey = Registry.LocalMachine.CreateSubKey(ODBCINST_INI_REG_PATH + "ODBC Drivers");
        if (driversKey == null) throw new Exception("ODBC Registry key for drivers does not exist");

        var driverNames = driversKey.GetValueNames();

        var ret = new List<string>();

        foreach (var driverName in driverNames)
        {
            if (driverName != "(Default)")
            {
                ret.Add(driverName);
            }
        }

        return ret.ToArray();
    }
}
6
задан marc_s 10 October 2009 в 07:30
поделиться

3 ответа

Для этого вы можете использовать XQuery - просто измените свой оператор на:

SELECT
   CAST(parms as xml).value('(/xml/@filename)[1]', 'varchar(260)') as p
FROM 
   dbo.Table1

Это дает вам VARCHAR (260), достаточно длинный для хранения любого допустимого имени файла и пути - теперь у вас есть строка и может работать с ним с SUBSTRING и т. д.

Marc

5
ответ дан 10 December 2019 в 00:41
поделиться

К сожалению, SQL Server не является соответствующей реализацией XQuery - скорее, это довольно ограниченное подмножество черновой версии спецификации XQuery. В нем не только нет fn: substring-before , но также нет fn: index-of , чтобы сделать это самостоятельно, используя fn: substring , ни fn: строка-код . Итак, насколько я могу судить, здесь вы застряли с SQL.

1
ответ дан 10 December 2019 в 00:41
поделиться

Самый простой способ сделать это - использовать SUBSTRING и CHARINDEX. Предполагая (мудро или нет), что первая часть имени файла не меняет длину, но вы по-прежнему хотите использовать XQuery для поиска имени файла, вот короткое повторение, которое делает то, что вы хотите:

declare @t table (
  parms varchar(max)
);
insert into @t values ('<xml filename="100100_456_484351864768.zip" event_dt="10/5/2009 11:42:52 AM"><info user="TestUser" /></xml>');

with T(fName) as (
  select cast(cast(parms as xml).query('data(/xml/@filename)') as varchar(100)) as p
  from @t
)
  select
    substring(fName,8,charindex('_',fName,8)-8) as myNum
  from T;

Есть хитрые решения, которые используйте другие строковые функции, такие как REPLACE и PARSENAME или REVERSE, но ни одна из них, вероятно, не будет более эффективной или удобочитаемой. Одна из возможностей - написать подпрограмму CLR, которая привносит обработку регулярных выражений в SQL.

Кстати, если ваш xml всегда такой простой, у меня нет особой причины использовать XQuery. Вот два запроса, которые извлекут нужное вам число. Второй вариант безопаснее, если у вас нет контроля над лишними пробелами в строке xml или над возможностью изменения длины первой части имени файла:

  select
    substring(parms,23,charindex('_',parms,23)-23) as myNum
  from @t;

  select
    substring(parms,charindex('_',parms)+1,charindex('_',parms,charindex('_',parms)+1)-charindex('_',parms)-1) as myNum
  from @t;
4
ответ дан 10 December 2019 в 00:41
поделиться