简体   繁体   English

如何将 SQL 查询字符串压缩为小于 258 个字符的小字符串?

[英]How do I compress a SQL query string to a small string less than 258 chars?

I want to create a unique small string <= 258 chars that is suitable as a windows filename.我想创建一个独特的小字符串 <= 258 个字符,适合作为 Windows 文件名。

This is to uniquely label a Xml query result.这是为了唯一标记一个 Xml 查询结果。

Here is a sample query:这是一个示例查询:

SELECT * FROM ( SELECT [utcDT],
MAX(CASE WHEN[Symbol] = 'fish' THEN[Close] END) AS [fish],
MAX(CASE WHEN[Symbol] = 'chips' THEN[Close] END) AS [chips]
FROM [DATA].[1M].[ASTS_NOGAP]
WHERE [Date] >= '2011-12-27'
AND [Date] <= '2012-07-01'
AND [Symbol] IN ('fish','chips')
GROUP BY [utcDT] ) AS A 
WHERE [utcDT] IS NOT NULL  AND [fish] IS NOT NULL AND [chips] IS NOT NULL 
ORDER BY [utcDT]

BUT is could be a longer query.但可能是一个更长的查询。

The compress is one way only, ie I do NOT need to decompress.压缩只是一种方式,即我不需要解压缩。

I want to end up with a unique file name like:我想以一个唯一的文件名结束,如:

 ksdgfsbhdfjksgdjbajysjdgyasagfdjahgdkjasgjgfjkgjkgdjkfgjskdjfgsajgdjfgjsgy.xml

EDIT1:编辑1:

The generated filename must be unique to the query - such that another app would generate the same filename for the same query.生成的文件名对于查询必须是唯一的 - 这样另一个应用程序将为相同的查询生成相同的文件名。

How can I achieve this?我怎样才能做到这一点?

There is a small risk for collisions, but this should do what you need:碰撞的风险很小,但这应该可以满足您的需求:

public string GetUniqueFileNameForQuery(string sql)
{
    using (var hasher = SHA256.Create())
    {
        var queryBytes = Encoding.UTF8.GetBytes(sql);
        var queryHash = hasher.ComputeHash(queryBytes);
                         // "/" may be included, but is not legal for file names
        return Convert.ToBase64String(queryHash).Replace("/", "-")+".xml";
    }
}

This needs using System.Security.Cryptography;这需要using System.Security.Cryptography; at the top of the file.在文件的顶部。


I also need to add a note about working with SQL from client code languages like C#.我还需要添加关于使用 C# 等客户端代码语言中的 SQL 的注释。

Most queries are going to need input of some kind: an ID field for a lookup, a date range, a username, something to tell the query which records you need out of a larger set.大多数查询要某种需要输入:一个ID字段的查询,日期范围,用户名,有事要告诉它记录你需要更大的一组进行查询。 It's very poor practice to substitute these inputs directly into the SQL string in your C# (or other language) code.将这些输入直接替换为 C#(或其他语言)代码中的 SQL 字符串是非常糟糕的做法 That opens you up to an issue known as SQL Injection, and it's kind of a big deal .这让您面临一个称为 SQL 注入的问题,这是一个大问题

Instead, for most all queries, there will be a placeholder variable name for each input argument.相反,对于大多数查询,每个输入参数都有一个占位符变量名称。 It matters for this question because you'll have the same SQL query text for two queries that differ only by arguments.这对这个问题很重要,因为对于仅参数不同的两个查询,您将拥有相同的 SQL 查询文本

For example, say you have this query:例如,假设您有以下查询:

 SELECT * FROM Users WHERE Username = @Username

You run this query twice, once with 'jsmith' as the input, and once with 'jdoe' .您运行此查询两次,一次使用'jsmith'作为输入,一次使用'jdoe' The SQL didn't change, and therefore the encoded file name didn't change. SQL 没有改变,因此编码的文件名没有改变。

You maybe be inclined to ask to get the value of the SQL after the parameter inputs are substituted into the query, but this misunderstands what happens.您可能倾向于将参数输入替换到查询中要求获取 SQL 的值,但这会误解会发生什么。 The parameter inputs are never, at any time, substituted into the sql query .参数输入在任何时候不会被替换到 sql 查询中 That's the whole point.这就是重点。 Even the database server will instead treat them as procedure variables.甚至数据库服务器也会将它们视为过程变量。

The point here is you also need a way to encode any parameter data used with your query.这里的重点是您还需要一种方法来对查询中使用的任何参数数据进行编码。 Here's one basic naive option:这是一个基本的天真的选项:

public string GetUniqueFileNameForQuery(DbCommand query)
{
    var sql = query.CommandText;
    foreach(var p in query.Parameters)
    {
        sql = sql.Replace(p.Name, p.Value.ToString());
    }

    using (var hasher = SHA256.Create())
    {
        var queryBytes = Encoding.UTF8.GetBytes(sql);
        var queryHash = hasher.ComputeHash(queryBytes);
                         // "/" may be included, but is not legal for file names
        return Convert.ToBase64String(queryHash).Replace("/", "-")+".xml";
    }
}

Note: this code could produce invalid SQL.注意:此代码可能会产生无效的 SQL。 For example, you might end up with something like this:例如,你可能会得到这样的结果:

SELECT * FROM Users WHERE LastName = O'Brien

But since you're not actually trying to run the query, that should be okay.但由于您实际上并没有尝试运行查询,所以应该没问题。 You also need to be careful with systems like OleDB, which uses positional matching and ?您还需要小心使用位置匹配和? for all parameter placeholders.对于所有参数占位符。 In this case, the parameter name won't match the placeholder, or even if it did, the first parameter would match the placeholder for all the others.在这种情况下,参数名称将与占位符不匹配,或者即使匹配,第一个参数也会与所有其他参数的占位符匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM