Оцените в T-SQL

У @Shashank правильная точка зрения. То, что вы хотите сделать, это отключить ввод специальных символов из бэкэнда, а также сделать поле недействительным из веб-интерфейса. Хакер, зная, что он делает, легко манипулирует самим HTTP-запросом, а не полем, что делает его довольно уязвимым.

Однако, если вы настаиваете на своем решении, я бы рекомендовал использовать RegEx. Это примерное выражение может пригодиться. Таким образом, всякий раз, когда поле ввода обнаруживает один из этих специальных символов, оно заменяет этот символ на ''

8
задан Joe Phillips 26 March 2009 в 17:27
поделиться

11 ответов

Считайте это... Проклятие и Благословения Динамического SQL, помогите мне большое понимание, как решить этот тип проблем.

16
ответ дан 3 November 2019 в 12:50
поделиться

Нет никакого "более опрятного" способа сделать это. Вы сэкономите время, если Вы примете его и посмотрите на что-то еще.

Править: Ага! Относительно комментария OP, что "Мы должны загрузить данные в новую базу данных каждый месяц или иначе это становится слишком большим".. удивляющий ретроспективно, который никто не отметил относительно слабого запаха этой проблемы.

SQL Server предлагает собственные механизмы для контакта с таблицами, которые становятся "слишком большими" (в частности, деля), который позволит Вам обращаться к таблице как к единственному объекту, при делении таблицы на отдельные файлы в фоновом режиме, таким образом устранении текущей проблемы в целом.

Другими словами, это - проблема для Вашего администратора DB, не потребителя DB. Если это, оказывается, Вы также, я предлагаю, чтобы Вы изучили разделение этой таблицы.

9
ответ дан 3 November 2019 в 12:50
поделиться

попробуйте sp_executesql, созданный в функции. Можно в основном создать строку SQL в proc, затем звонить

exec sp_executesql @SQLString.

DECLARE @SQLString nvarchar(max)
SELECT @SQLString = '
SELECT *
FROM  ' +  @TableName 

EXEC sp_executesql @SQLString
5
ответ дан 3 November 2019 в 12:50
поделиться

Вы не можете указать динамическое имя таблицы в SQL Server.

Существует несколько опций:

  1. Используйте динамический SQL
  2. Игра вокруг с синонимами (что означает менее динамический SQL, но все еще некоторых),

Вы сказали, что Вам не нравится 1, поэтому отпускает для 2.

Первая опция состоит в том, чтобы ограничить грязность одной строкой:

begin transaction t1;
declare @statement nvarchar(100);

set @statement = 'create synonym temptablesyn for db1.dbo.test;'
exec sp_executesql @statement

select * from db_syn

drop synonym db_syn;

rollback transaction t1;

Я не уверен, что мне нравится это, но это может быть Ваш наилучший вариант. Таким образом, все ВЫБОРЫ будут тем же.

Можно осуществить рефакторинг это к содержанию основ, но существует много недостатков к этому, включая синоним создается в транзакции, таким образом, у Вас не может быть двух из запросов, работающих одновременно (потому что оба будут пытаться создать temptablesyn). В зависимости от стратегии блокировки каждый заблокирует другой.

Синонимы являются постоянными, таким образом, это - то, почему необходимо сделать это в транзакции.

2
ответ дан 3 November 2019 в 12:50
поделиться

Существует несколько опций, но они более грязны, чем способ, которым Вы уже делаете. Я предлагаю Вас также:
(1) Палка с текущим подходом
(2) Идите вперед и встройте SQL в код, так как Вы делаете его так или иначе.
(3) Будьте дополнительны осторожный для проверки входа для предотвращения Внедрения SQL.

Кроме того, беспорядок не является единственной проблемой с динамическим SQL. Помните следующее:
(1) Динамический SQL мешает способности сервера создать допускающий повторное использование план выполнения.
(2) Команда ExecuteSQL повреждает цепочку принадлежности. Это означает, что код будет работать в контексте пользователя, который называет хранимую процедуру НЕ владельцем процедуры. Это могло бы вынудить Вас открыть безопасность на любой таблице, против которой работает оператор, и создайте другие проблемы безопасности.

1
ответ дан 3 November 2019 в 12:50
поделиться

Просто мысль, но если у Вас был предопределенный список этих баз данных, затем Вы могли бы создать единственное представление в базе данных, что Вы соединяетесь с присоединиться к ним - что-то как:

CREATE VIEW dbo.all_tables
AS

SELECT  your_columns,
        'db_name1' AS database_name
FROM    db_name1.dbo.your_table

UNION ALL

SELECT  your_columns,
        'db_name2'
FROM    db_name2.dbo.your_table

etc...

Затем Вы могли передать свое имя базы данных в Вашей хранимой процедуре и просто использовать его в качестве параматери в операторе Where. Если таблицы являются большими, Вы могли бы рассмотреть использование индексного представления, индексированного на новом database_name столбце (или независимо от того, что Вы называете его), и первичный ключ таблиц (я предполагаю от вопроса, что схемы таблиц являются тем же?).

Очевидно, если Ваш список базы данных часто изменяется, то это становится более проблематичным - но если необходимо создать эти базы данных так или иначе, затем поддержание этого представления одновременно не должно быть слишком большим количеством издержек!

1
ответ дан 3 November 2019 в 12:50
поделиться

Я думаю, что Mark Brittingham имеет верное представление (здесь: http://stackoverflow.com/questions/688425/evaluate-in-t-sql/718223#718223), который является к проблеме a use database управляйте и запишите SP для НЕ полного определения имени таблицы. Как он отмечает, это будет действовать на таблицы в текущей базе данных входа в систему.

Позвольте мне добавить несколько возможных разработок:

Из комментария OP я заключаю, что база данных изменяется один раз в месяц, когда это становится "слишком большим". ("Мы должны загрузить данные в новую базу данных каждый месяц, или иначе это становится слишком большим. – d03boy")

  1. Пользовательские логины имеют базу данных по умолчанию, устанавливают с (удержанным от использования) sp_defaultdb или ИЗМЕНЯЮТ ВХОД В СИСТЕМУ. Если каждый месяц Вы идете дальше к новой базе данных, и не должны выполнить SP на более старых копиях, просто изменить дб входа в систему по умолчанию ежемесячно, и снова, не полностью определяйте имя таблицы.

  2. База данных для использования может быть установлена в клиентском входе в систему: sqlcmd -U login_id -P password -d db_name, затем должностное лицо SP оттуда.

  3. Можно установить соединение с базой данных с помощью клиента по Вашему выбору (командная строка, ODBC, JDBC), затем проблема a use database команда, должностное лицо SP.

    используйте панель базы данных; должностное лицо sp_foo;

После того как база данных была установлена с помощью одного из вышеупомянутого, у Вас есть три варианта для выполнения хранимой процедуры:

  1. Вы могли просто скопировать SP наряду с базой данных, в к новой базе данных. Пока имя таблицы НЕ полностью определяется, Вы будете воздействовать на таблицу новой базы данных.

    должностное лицо sp_foo;

  2. Вы могли установить единственную каноническую копию SP в его собственной базе данных, назвать его procs, с именем таблицы, не полностью определенным, и затем, называют его полностью полностью определенное имя:

    должностное лицо procs.dbo.sp_foo;

  3. Вы, в каждой отдельной базе данных, могли установить тупик sp_foo то, что должностные лица полностью определенное название реального SP и затем должностное лицо sp_foo не квалифицируя его. Тупик назовут, и он призовет реальную процедуру procs. (К сожалению, use database dbname не может быть выполнен из SP.)

    --sp_foo stub:
    create proc bar.dbo.sp_foo 
     @parm int
    as
    begin
      exec procs.dbo.sp_foo @parm;
    end
    go

Однако это сделано, если база данных изменяется, реальный SP должен быть создан с WITH RECOMPILE опция, иначе это будет кэшировать план выполнения относительно неправильной таблицы. Тупику, конечно, не нужно это.

1
ответ дан 3 November 2019 в 12:50
поделиться

Вы могли создать CLR SQL Табличный UDF для доступа к таблицам. Необходимо связать его со схемой, потому что ТВ-UDFs не поддерживает динамическую схему. (Мой образец включает идентификатор, и столбец Title - изменяют для Ваших потребностей),

После того как Вы сделали это, необходимо смочь сделать следовать запрос:

SELECT * FROM dbo.FromMyTable('table1')

Можно включать многослойное имя в ту строку также.

SELECT * FROM dbo.FromMyTable('otherdb..table1')

возвратить идентификатор, столбцы Title от той таблицы.

Необходимо будет, вероятно, включить SQL CLR и включить опцию TRUSTWORTHY:

sp_configure 'clr enabled',1
go
reconfigure
go
alter database mydatabase set trustworthy on

Создайте Проект SQL C#, добавьте новый файл UDF, вставьте это там. Установите Свойство проекта, Базу данных, Уровень Разрешения к внешнему. Создайте, развернитесь. Может обойтись без VisualStudio. Сообщите мне, нужно ли Вам это.

using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Data.SqlClient;

[assembly: CLSCompliant(true)]
namespace FromMyTable
{
    public static partial class UserDefinedFunctions
    {
        [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read, IsDeterministic = true, SystemDataAccess = SystemDataAccessKind.Read, IsPrecise = true, FillRowMethodName = "FillRow", 
            TableDefinition = "id int, title nvarchar(1024)")]
        public static IEnumerable FromMyTable(SqlString tableName)
        {
            return new FromMyTable(tableName.Value);
        }

        public static void FillRow(object row, out SqlInt32 id, out SqlString title)
        {
            MyTableSchema v = (MyTableSchema)row;
            id = new SqlInt32(v.id);
            title = new SqlString(v.title);
        }
    }

    public class MyTableSchema
    {
        public int id;
        public string title;
        public MyTableSchema(int id, string title) { this.id = id; this.title = title; }
    }

    internal class FromMyTable : IEnumerable
    {
        string tableName;

        public FromMyTable(string tableName)
        {
            this.tableName = tableName;
        }

        public IEnumerator GetEnumerator()
        {
            return new FromMyTableEnum(tableName);
        }
    }

    internal class FromMyTableEnum : IEnumerator
    {
        SqlConnection cn;
        SqlCommand cmd;
        SqlDataReader rdr;
        string tableName;

        public FromMyTableEnum(string tableName)
        {
            this.tableName = tableName;
            Reset();
        }

        public MyTableSchema Current
        {
            get { return new MyTableSchema((int)rdr["id"], (string)rdr["title"]); }
        }

        object IEnumerator.Current
        {
            get { return Current; }
        }

        public bool MoveNext()
        {
            bool b = rdr.Read();
            if (!b) { rdr.Dispose(); cmd.Dispose(); cn.Dispose(); rdr = null; cmd = null; cn = null; }
            return b;
        }

        public void Reset()
        {
            // note: cannot use a context connection here because it will be closed
            // in between calls to the enumerator.
            if (cn == null) { cn = new SqlConnection("server=localhost;database=mydatabase;Integrated Security=true;"); cn.Open(); }
            if (cmd == null) cmd = new SqlCommand("select id, title FROM " + tableName, cn);
            if (rdr != null) rdr.Dispose();
            rdr = cmd.ExecuteReader();
        }
    }
}
1
ответ дан 3 November 2019 в 12:50
поделиться
declare @sql varchar(256);
set @sql = 'select * into ##myGlobalTemporaryTable from '+@dbname
exec sp_executesql @sql

select * from ##myGlobalTemporaryTable

копии в глобальную временную таблицу, которую можно затем использовать как постоянный столик

0
ответ дан 3 November 2019 в 12:50
поделиться

Если у Вас есть довольно управляемое количество баз данных, может быть лучше использовать предопределенный условный оператор как:

if (@dbname = 'db1')
  select * from db1..MyTable
if (@dbname = 'db2')
  select * from db2..MyTable
if (@dbname = 'db3')
  select * from db3..MyTable

...

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

Это избегает проблем безопасности с динамическим sql. Можно также улучшить производительность путем замены 'избранных' операторов хранимыми процедурами, предназначающимися для каждой базы данных (1 кэшируемый план выполнения на запрос).

0
ответ дан 3 November 2019 в 12:50
поделиться
if exists (select * from master..sysservers where srvname = 'fromdb')
    exec sp_dropserver 'fromdb'
go

declare @mydb nvarchar(99);
set @mydb='mydatabase'; -- variable to select database

exec sp_addlinkedserver @server = N'fromdb',
    @srvproduct = N'',
    @provider = N'SQLOLEDB', 
    @datasrc = @@servername,
    @catalog = @mydb
go

select * from OPENQUERY(fromdb, 'select * from table1') 
go 
0
ответ дан 3 November 2019 в 12:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: