如何获取大于多列值的值,而不是使用SQL Server中的复合键字段

时间:2019-02-07 11:13:41

标签: c# sql sql-server

如果我的表包含以下数据:

分支,类型,数字=>这将生成复合键字符串'keyfield'

分支的长度,类型为[int] [4]
数字的长度是[int] [7]

数据是这样的:

branch, type, number
13,     1309,   1    row1
13,     1309,   2    row2
13,     1310,   1    row3
14,     1309,   1    row4

所以我有keyfield->称为'KeyField'列,但是idont需要使用它,它可以工作,但是我只需要使用表达式而不是字符串keyfield 例如:
如果我需要使行大于上面的row2: 我写道:

SELECT TOP 1 * FROM TABLE WHERE KeyField > '0013130900002'

->我不喜欢使用字符串作为复合键..

我也不能像这样手动创建它:

SELECT TOP 1 * FROM  TABLE WHERE brn > 1 AND type > 1309 and num > 2

这行不通...所以我只需要通过表达式获取下一行

例如:getGreatRow(1,1309,2); //这将返回row3我需要做的。 这样该功能可以直接与C#和屏幕上的文本框一起使用! 我需要选择唯一的前1个记录,该记录大于我指定的当前记录或表达式的值。

修改

我根据需要使用Gordon SQL生成带有主键列表的C#。感谢戈登。

在C#中自动生成SQL查询:

public List<EntryTable> Tables { get; private set; }
public List<BufferElement> Buffer { get; private set; }
 string Query = string.Empty;
                    for (int i = 0; i < Tables[0].PrimaryKeys.Count; i++)
                    {
                        Query += "(";
                        for (int j = 0; j < i; j++)
                        {
                            switch (Tables[0].PrimaryKeys[j].CLRType)
                            {
                                case CLRType.CLR_BYTE:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToByte(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_INT16:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToInt16(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_INT32:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToInt32(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_INT64:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToInt64(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_SINGLE:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToSingle(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_DOUBLE:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToDouble(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_DECIMAL:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToDecimal(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_Boolean:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = {Convert.ToBoolean(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)} AND ";
                                    break;
                                case CLRType.CLR_STRING:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = '{Convert.ToString(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)}' AND ";
                                    break;
                                case CLRType.CLR_DATETIME:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = '{Convert.ToDateTime(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)}' AND ";
                                    break;
                                case CLRType.CLR_TIME:
                                    Query += $"{Tables[0].PrimaryKeys[j].KeyPart} = '{TimeSpan.Parse(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[j].KeyPart).Value)}' AND ";
                                    break;
                            }
                        }

                        switch (Tables[0].PrimaryKeys[i].CLRType)
                        {
                            case CLRType.CLR_BYTE:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToByte(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_INT16:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToInt16(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_INT32:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToInt32(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_INT64:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToInt64(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_SINGLE:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToSingle(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_DOUBLE:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToDouble(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_DECIMAL:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToDecimal(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_Boolean:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > {Convert.ToBoolean(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}";
                                break;
                            case CLRType.CLR_STRING:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > '{Convert.ToString(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}'";
                                break;
                            case CLRType.CLR_DATETIME:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > '{Convert.ToDateTime(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}'";
                                break;
                            case CLRType.CLR_TIME:
                                Query += $"{Tables[0].PrimaryKeys[i].KeyPart} > '{TimeSpan.Parse(Buffer.Find(x => x.ID == Tables[0].PrimaryKeys[i].KeyPart).Value)}'";
                                break;
                        }
                        Query += $") {(Tables[0].PrimaryKeys.Count > 1 && i != Tables[0].PrimaryKeys.Count - 1 ? " OR " : string.Empty)} \n";
                    }

                    Query += $"ORDER BY {string.Join(" ASC, ", Tables[0].PrimaryKeys.Select(x => x.KeyPart).ToArray())} ASC";

                    SelectCommand = $"SELECT TOP 1 * FROM {Tables[0].Table} WHERE " + Query;

4 个答案:

答案 0 :(得分:0)

如果您尝试获取1, 1309, 2之后的下一行

SELECT TOP 1 *
FROM TABLE
WHERE brn > 1 OR
      (brn = 1 AND type > 1309) OR
      (brn = 1 AND type = 1309 AND num > 2)
ORDER BY brn DESC, type DESC, num DESC;

答案 1 :(得分:0)

我建议您使用“数学”:将列按“相关顺序”放置,然后相乘以在单个字段中容纳所有数字。例如: new_id=first_column*100000+second_column*10+third_column

因此,在第1行的情况下,您将获得1313091作为代码。数学比字符串处理要快得多。然后,您将能够查询将密钥除以所需的部分。最终在您认为会增长很多的列上添加更多零。

当您使用列构建键以保持外部顺序时,顺序会保留。

因此您的查询将类似于:

select *
from table
where new_id > (branch)*100000+(type)*10+number 

IDEA是这样的:

123456 99349199 12341234 : having enough space for a 'reasonable' amount of numbers
000000 00000000 00000000

so 123456 x 1 00000000 00000000  = 123456 00000000 00000000  +

   99349199 x 1 00000000         =        99349199 00000000  +
and
   12341234 x                      1 =            12341234  =                  
                                  -------------------------
                                  123456 99349199 12341234

已更新:

select *
from my_table
WHERE new_id (branch)*1 00000000 00000000+(type)*1 00000000+number 

显然我们的“ new_label”定义已更改:

new_label= (branch)*100000000 00000000+(type)*100000000 + number

因此您可以拥有以下最大长度:

<all digits you want> (branch) + 8 digit (type) + 8 digit (number)

我建议您添加数据库触发器以强制执行这些最大限制

答案 2 :(得分:0)

在数据库中创建此功能

CREATE FUNCTION dbo.GetCompositeKey(@branch int, @type int, @number int)
RETURNS bigint
AS
BEGIN
    RETURN cast(@branch as bigint) * 100000000000 + cast(@type as bigint) * 10000000 + @number
END

,然后在进行比较时使用它,如下所示:

SELECT TOP 1 * FROM [TABLE]
WHERE dbo.GetCompositeKey(branch, type, number) > 
      dbo.GetCompositeKey(13, 1309, 2)        
ORDER BY dbo.GetCompositeKey(branch, type, number)

注意:为简化说明,此查询经过简化。从C#执行时,应使用参数化查询为SQL函数提供3个整数,以避免SQL注入攻击。


编辑:发布此内容后,我读了一些其他答案的评论,其中您说您不懂数学。到目前为止,在大多数答案中,方法只是创建一个将所有三个值(分支,类型和数字)组合在一起以创建可比较值的大整数。实际上,这与在您的问题('0013130900002')中使用字符串连接和基于字符串的复合键的操作相同。正如另一个答案中指出的那样,数学方法应该更快。字符串中的另一个错误是将@number字段仅零填充为5位数字,当您已经声明它必须能够容纳7位数字时。

可以肯定的是,到目前为止,所有答案都使用非常基础的数学。如果您不懂基本的数学知识,您将无法像一名程序员那样步履维艰,因此您应该优先考虑提高该技能。

答案 3 :(得分:0)

您在对其他答案的评论中说,您不想填充数据集或使用MoveNext等。另一种方法是创建一个包含复合键的视图。

首先,创建我在my other answer中定义的函数

然后,创建视图

CREATE VIEW [myview]
AS
SELECT 
    *,
    dbo.GetCompositeKey(branch, type, number) as CompositeKey
FROM [table]

像这样查询它:

SELECT TOP 1 * FROM [myview] 
WHERE CompositeKey > dbo.GetCompositeKey(13, 1309, 2)        
ORDER BY CompositeKey

这种方法可能会比我的其他答案提高查询性能。您需要对其进行测试才能找到答案。