1

对 SQL 很陌生,在这里使用烧瓶和 sqlalchemy 是我的问题(我希望它不会太长)

概述:

我有一个结构如下的 SQL 表:

name    vector       axis       value       unit    ref 
----------------------------------------------------------------    
name1       v1          W       46504       psi     ref1
name1       v1          L       51757       psi     ref1
name1       v2          W         127       psi     another ref
name1       v2          L         403       psi     ref1
name2 ...

name我的目标是“取消堆叠”结果,例如只要unit并且ref相同,我就可以拥有一行。

例如,我希望得到类似的东西:

name      v1-L      v2-W    v1-L    v2-W    unit    ref
--------------------------------------------------------------
name1    46504               127    403     psi    ref1
name1                127                    psi    another ref
name2...

尝试使用 sqlalchemy:

到目前为止,我尝试根据“名称”加入同一张表——现在,两者都没有检查unit—— ref

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Table, Text, Date, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import  sessionmaker, aliased
engine = create_engine('sqlite://') #, echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

class Test(Base):
    __tablename__ = 'test'
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    vector = Column(String(32))
    axis = Column(String(1))
    value = Column(Float)
    unit = Column(String(16), default='psi')
    ref = Column(String(32))

Base.metadata.create_all(engine)

# some data to play with
data = [{'name':'name1', 'vector':'v1', 'axis':'W', 'value':'46504', 'unit':'psi', 'ref':'ref1'},
        {'name':'name1', 'vector':'v1', 'axis':'L', 'value':'51757', 'unit':'psi', 'ref':'ref1'},
        {'name':'name1', 'vector':'v2', 'axis':'W', 'value':'127', 'unit':'psi', 'ref':'another ref'},
        {'name':'name1', 'vector':'v2', 'axis':'L', 'value':'403', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v1', 'axis':'L', 'value':'23000', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v1', 'axis':'W', 'value':'27000', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v2', 'axis':'L', 'value':'523', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v2', 'axis':'W', 'value':'217', 'unit':'psi', 'ref':'ref1'},]
for dic in data:
    t = Test(**dic)
    session.add(t)
session.commit()

test_alias = aliased(Test)
q = session.query(Test.id, Test.name, Test.value).filter(Test.vector == 'v1').\
    join(test_alias, Test.name).filter(test_alias.vector == 'v2')
print q

使用熊猫的示例:

这是我使用pandas库会得到的。

import pandas as pd
q = session.query(Test).order_by(Test.id) # that is the default table
row2dict = lambda r: {c.name: getattr(r, c.name) for c in r.__table__.columns}
df = pd.DataFrame([row2dict(i) for i in q])
df = df.drop(['id'], axis=1)

df = df.set_index(['ref', 'unit', 'name', 'vector', 'axis']).sort()
df = df.unstack(level=-2).unstack(level=-1)['value'].reset_index()
print(df)

vector          ref unit   name     v1          v2     
axis                                 L      W    L    W
0       another ref  psi  name1    NaN    NaN  NaN  127
1              ref1  psi  name1  51757  46504  403  NaN
2              ref1  psi  name2  23000  27000  523  217

...这与我的预期相差不远。

那么用 SQL 语言来做这件事有意义吗?因此,我的以下问题是:使用Flask框架,使用 pandas 进行数据处理有意义吗?还是我应该坚持使用 SQL 语言?

4

2 回答 2

3

熊猫可能更适合这种事情。可能有一些更奇特的 SQL 函数可以进行这样的转换,但我不确定。下面是您使用最简单方法的示例,它只是将每个视图连接在一起。想到的方式是,由于您正在生成具有从数据派生的“虚拟”列的行,这表明正在从更基本的行创建复合行。所以下面的方法分解出一组对应于四个条件的行,v1/W、v1/L、v2/W、v2/L。现在,如果在实践中,有任意数量的“vN”,那可能是 Pandas 的转换能力更合适的地方。

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, aliased

Base = declarative_base()

class Test(Base):
    __tablename__ = 'test'
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    vector = Column(String(32))
    axis = Column(String(1))
    value = Column(Float)
    unit = Column(String(16), default='psi')
    ref = Column(String(32))

engine = create_engine('sqlite://', echo=True)
session = Session(engine)

Base.metadata.create_all(engine)

# some data to play with
data = [{'name':'name1', 'vector':'v1', 'axis':'W', 'value':'46504', 'unit':'psi', 'ref':'ref1'},
        {'name':'name1', 'vector':'v1', 'axis':'L', 'value':'51757', 'unit':'psi', 'ref':'ref1'},
        {'name':'name1', 'vector':'v2', 'axis':'W', 'value':'127', 'unit':'psi', 'ref':'another ref'},
        {'name':'name1', 'vector':'v2', 'axis':'L', 'value':'403', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v1', 'axis':'L', 'value':'23000', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v1', 'axis':'W', 'value':'27000', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v2', 'axis':'L', 'value':'523', 'unit':'psi', 'ref':'ref1'},
        {'name':'name2', 'vector':'v2', 'axis':'W', 'value':'217', 'unit':'psi', 'ref':'ref1'},]
for dic in data:
    t = Test(**dic)
    session.add(t)
session.commit()

axis_w = session.query(Test).filter(Test.axis == "W")
axis_l = session.query(Test).filter(Test.axis == "L")
axis_v1_w = axis_w.filter(Test.vector == "v1").subquery()
axis_v1_l = axis_l.filter(Test.vector == "v1").subquery()
axis_v2_w = axis_w.filter(Test.vector == "v2").subquery()
axis_v2_l = axis_l.filter(Test.vector == "v2").subquery()

def join_axes(left, right):
    return and_(
                left.c.unit == right.c.unit,
                left.c.ref == right.c.ref
            )

name_unit_ref = session.query(Test.name, Test.unit, Test.ref).distinct().subquery()

q = session.query(name_unit_ref.c.name,
                axis_v1_w.c.value.label('v1_w'),
                axis_v1_l.c.value.label('v1_l'),
                axis_v2_w.c.value.label('v2_w'),
                axis_v2_l.c.value.label('v2_l'),
                name_unit_ref.c.unit,
                name_unit_ref.c.ref
            ).\
            outerjoin(axis_v1_w, join_axes(name_unit_ref, axis_v1_w)).\
            outerjoin(axis_v1_l, join_axes(name_unit_ref, axis_v1_l)).\
            outerjoin(axis_v2_w, join_axes(name_unit_ref, axis_v2_w)).\
            outerjoin(axis_v2_l, join_axes(name_unit_ref, axis_v2_l))

for row in q:
    print row
于 2013-12-25T19:55:57.540 回答
0

对于您的问题,这是更“异国情调”的 SQL。我正在使用 SQL Server 2008+ 来获取 PIVOT 命令。我不确定它是否完全涵盖了您的专栏的情况。

--Setup the table and data
create table #t
(
 name nvarchar(100) not null
,vector char(2) not null
,axis char(1) not null
,value int not null
,unit char(3) not null
,ref nvarchar(100) not null
);

insert into #t values ('name1','v1','W', 46504,'psi','ref1');
insert into #t values ('name1','v1','L', 51757,'psi','ref1');
insert into #t values ('name1','v2','W',   127,'psi','another ref');
insert into #t values ('name1','v2','L',   403,'psi','ref1');

-- Retrieve the data using SQL Server Pivot
-- http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
select * 
from 
(select 
  name
 ,vector + '-' + axis as vector_axis
 ,value
 ,unit
 ,ref
 from #t) as t
pivot (sum(value) for vector_axis IN
([v1-w]
,[v1-L]
,[v2-W]
,[v2-L]
)
) as p

在此处输入图像描述

于 2013-12-27T16:37:47.943 回答