SQLite中一行与另一行的比较

时间:2011-06-09 01:08:53

标签: android sql sqlite

我有一个Android应用。在我的Android应用程序中,我有一个SQLite数据库。在我的SQLite数据库中,我有一个如下所示的表:

_id    a    b    c    d
 1     1    1    1    0
 2     0    1    1    1
 3     1    0    0    1
 4     0    1    0    1

我想计算每一行:在当前或上一行中有一个1的所有列a,b,c和d,当前和上一行中有一个1的百分比是多少?输出看起来像这样:

_id    a    b    c    d    result
 1     1    1    1    0    NULL
 2     0    1    1    1    50%
 3     1    0    0    1    25%
 4     0    1    0    1    33%

我可以在SQLite之外的Java中执行此操作,但我宁愿在SQL中执行此操作;它会更整洁。我应该使用什么查询?

1 个答案:

答案 0 :(得分:4)

Select  CurAndNext.T1_id
    , Sum( Case When D1.Val + D2.Val = 1 Then 1 End ) As CntInEitherRow
    , Sum( Case When D1.Val + D2.Val = 2 Then 1 End ) / 4.000 As PercBoth
From    (
        Select T1._id As T1_id, Max( T2._id ) As T2_id
        From MyTable As T1
            Left Join MyTable As T2
                On T2._id < T1._id
        Group By T1._id
        ) As CurAndNext
    Join    (
            Select _id, 'a' As Col, a As Val From MyTable As T1
            Union All
            Select _id, 'b', b From MyTable As T1
            Union All
            Select _id, 'c', c From MyTable As T1
            Union All
            Select _id, 'd', d From MyTable As T1
            ) As D1
        On D1._id = CurAndNext.T1_id
    Left Join   (
                Select _id, 'a' As Col, a As Val From MyTable As T1
                Union All
                Select _id, 'b', b From MyTable As T1
                Union All
                Select _id, 'c', c From MyTable As T1
                Union All
                Select _id, 'd', d From MyTable As T1
                ) As D2
            On D2._id = CurAndNext.T2_id
                And D2.Col = D1.Col
Group By CurAndNext.T1_Id

使查询困难的一个重要因素是数据被非规范化。因此,我必须将其标准化才能获得您所寻求的信息。


了解哪些列abcd代表了世界上的所有差异。上述查询的复杂性表明模式不能很好地映射到业务需求。知道他们代表学生出勤,我们可以设计一个替代模式。

Create Table Student
    (
    Id int not null Primary Key
    , Name varchar(50) not null
    )

Create Table Class
    (
    Id int not null Primary Key
    , Name varchar(50) not null
    )

-- if using dates, this would be the equivalent
-- of a calendar table
Create Table ClassDay 
    ( 
    DayNum int not null Primary Key 
    )

-- ClassDayNum would be better as a Date    
Create Table Attendence
    (
    StudentId int References Student( Id )
    , ClassId int References Class( Id )
    , ClassDayNum int not null  References ClassDay( DayNum )
    , Unique( StudentId, ClassId, ClassDayNum )
    )

Insert Student( Id, Name )
Select 1, 'a'
Union All Select 2, 'b'
Union All Select 3, 'c'
Union All Select 4, 'd'

Insert Class( Id, Name )
Values (1, 'Some Class' )

Insert ClassDay( DayNum )
Select 1
Union All Select 2
Union All Select 3
Union All Select 4

Insert Attendence( ClassId, StudentId, ClassDay )
Select 1, 1, 1
Union All Select 1, 1, 3
Union All Select 1, 2, 1
Union All Select 1, 2, 2
Union All Select 1, 2, 4
Union All Select 1, 3, 1
Union All Select 1, 3, 2
Union All Select 1, 4, 2
Union All Select 1, 4, 3
Union All Select 1, 4, 4
  
    所有a,b,c和d列中当前或前一行都有1的

  

您的结果实际读取的方式是请求一天而不是之前的或前一天而不是当前的人数。< / p>

Select Class.Id, ClassDay.DayNum
    , Count(Distinct A.StudentId) As Attendence
    , Count(Distinct A.StudentId) / 4.000 As Ratio
From Class
    Cross Join Student
    Cross Join ClassDay
    Left Join Attendence As A
        On A.ClassId = Class.Id
            And A.StudentId = Student.Id
            And A.ClassDayNum = ClassDay.DayNum
            And A.ClassDayNum > 1
    Left Join Attendence As A2
        On A2.ClassId = Class.Id
            And A2.StudentId = Student.Id
            And A2.ClassDayNum = ClassDay.DayNum - 1
Where Not( A.StudentId Is Not Null And A2.StudentId Is Not Null )
Group By Class.Id, ClassDay.DayNum

结果:

DayNum  Attendence | Ratio
1      |    0      |   0
2      |    1      |   .25
3      |    1      |   .25
4      |    1      |   .25
  
    

当前和上一行中有1的百分比

  
Select ClassDay.DayNum
    , Sum( Case When A.StudentId Is Not Null And A2.StudentId Is Not Null Then 1 End )
    , Sum( Case When A.StudentId Is Not Null And A2.StudentId Is Not Null Then 1 End ) / 4.000
From Class
    Cross Join Student
    Cross Join ClassDay
    Left Join Attendence As A
        On A.ClassId = Class.Id
            And A.StudentId = Student.Id
            And A.ClassDayNum = ClassDay.DayNum
            And A.ClassDayNum > 1
    Left Join Attendence As A2
        On A2.ClassId = Class.Id
            And A2.StudentId = Student.Id
            And A2.ClassDayNum = ClassDay.DayNum - 1
Group By ClassDay.DayNum            
DayNum | Attendence | Ratio
1      |    NULL    |  NULL
2      |    2       |  0.500000
3      |    1       |  0.250000
4      |    1       |  0.250000