我有一些非标准化的数据,我正在尝试将列打开,我希望你们都能帮我找出最好的方法。我使用多个union语句完成了这个,但我希望做的是创建一个动态查询,可以在表中添加更多列时反复执行此操作。我的数据看起来像这样:(数字列一直到50)
| Code | Desc | Code_0 | Desc_0| Period| 1 | 2 | 3 | 4 |
|-------|-------|--------|-------|-------|---------|--------|---------|----------|
| NULL | NULL | NULL | NULL | Date |29-Nov-13|6-Dec-13|13-Dec-13| 20-Dec-13|
|CTR07 |Risk | P1 | Phase1| P | 0.2 | 0.4 | 0.6 | 1.1 |
|CTR07 |Risk | P1 | Phase1| F | 0.2 | 0.4 | 0.6 | 1.1 |
|CTR07 |Risk | P1 | Phase1| A | 0.2 | 0.4 | 0.6 | 1.1 |
|CTR08 |Oper | P1 | Phase1| P | 0.6 | 0.6 | 0.9 | 2.7 |
|CTR08 |Oper | P1 | Phase1| F | 0.6 | 0.6 | 0.9 | 2.7 |
|CTR08 |Oper | P1 | Phase1| A | 0.6 | 0.6 | 0.9 | 2.7 |
列标题是顶行。正如您所看到的那样,有些奇怪之处需要与之相提并论。
日期字段开始之前的前四个NULL列是个问题。每个具有数字标题(1-50)的列代表一周。问题在于,每周不仅有日期字段,还有同一列中该周的百分比值。我想让它向下旋转,看起来像这样:
| Code | Desc |Code_0 |Desc_0 | Period| Date |Percent|
|-------|-------|-------|-------|-------|---------|-------|
|CTR07 | Risk | P1 | Phase | P | 11/29/13| 0.2 |
|CTR07 | Risk | P1 | Phase1| F | 11/29/13| 0.2 |
|CTR07 | Risk | P1 | Phase1| A | 11/29/13| 0.2 |
|CTR08 | Oper. | P1 | Phase1| P | 11/29/13| 0.6 |
每周的日期在其自己的列中,百分比按其各自的日期分组。
由不同的代码,描述,CODE_0,期间和日期键入。我想将日期与数字列中的百分比分开,然后将数字列放入按日期连接的自己的列中。正如我之前所说,我已经使用UNION语句静态地完成了它,但是我想编写某种查询,在表扩展时动态地执行它。任何帮助将不胜感激。如果您需要任何其他信息,请告诉我,这是我在StackOverflow上的第一个问题,我有两个很好的截图可以告诉您,但我还没达到10个。仅限科幻和幻想。我知道,对吧?
我在联合中用来静态创建底部表的代码:
select `Code`, `Desc`, `Code_0`, `Desc_0`, `Period`, (select STR_TO_DATE(`1`, '%d%b%y') from combined_complete where `1` = '29Nov13') as `Date`, `1` as `Percent`
from combined_complete
where period <> 'Date'
union
select `Code`, `Desc`, `Code_0`, `Desc_0`, `Period`, (select STR_TO_DATE(`2`, '%d%b%y') from combined_complete where `2` = '06Dec13') as `Date`, `2`
from combined_complete
where period <> 'Date'
union
select `Code`, `Desc`, `Code_0`, `Desc_0`, `Period`, (select STR_TO_DATE(`3`, '%d%b%y') from combined_complete where `3` = '13Dec13') as `Date`, `3`
from combined_complete
where period <> 'Date'
union
select `Code`, `Desc`, `Code_0`, `Desc_0`, `Period`, (select STR_TO_DATE(`4`, '%d%b%y') from combined_complete where `4` = '20Dec13') as `Date`, `4`
from combined_complete
where period <> 'Date'
答案 0 :(得分:2)
对于这个建议,我创建了一个名为TransPoser
的简单50行表,可能已经有一个MySQL或你的数据库中可用的整数表,但是你想要一些类似于你的数字1到N的表对于那些编号的列。
然后,使用该表,交叉连接到非规范化表(我将其称为BadTable),但将其限制为第一行。然后使用一组case表达式pivot
将那些日期字符串放入一列。如果需要,我们可以将其转换为正确的日期(我建议,但不包括它)。
然后将这个小转置用作主查询中的派生表。
主查询忽略第一行,但也使用交叉连接将所有原始行强制为50行(或者如本例中所示,为4行)。然后将该笛卡尔积与该上述的派生表连接以提供日期。然后是另一组案例表达式,它将百分比转换为一个列,与日期和各种代码对齐。
示例结果(来自样本数据),手动添加空行:
| N | CODE | DESC | CODE_0 | DESC_0 | THEDATE | PERCENTAGE |
|---|-------|------|--------|--------|-----------|------------|
| 1 | CTR07 | Risk | P1 | Phase1 | 29-Nov-13 | 0.2 |
| 1 | CTR07 | Risk | P1 | Phase1 | 29-Nov-13 | 0.2 |
| 1 | CTR07 | Risk | P1 | Phase1 | 29-Nov-13 | 0.2 |
| 1 | CTR08 | Oper | P1 | Phase1 | 29-Nov-13 | 0.6 |
| 1 | CTR08 | Oper | P1 | Phase1 | 29-Nov-13 | 0.6 |
| 1 | CTR08 | Oper | P1 | Phase1 | 29-Nov-13 | 0.6 |
| 2 | CTR07 | Risk | P1 | Phase1 | 6-Dec-13 | 0.4 |
| 2 | CTR07 | Risk | P1 | Phase1 | 6-Dec-13 | 0.4 |
| 2 | CTR07 | Risk | P1 | Phase1 | 6-Dec-13 | 0.4 |
| 2 | CTR08 | Oper | P1 | Phase1 | 6-Dec-13 | 0.6 |
| 2 | CTR08 | Oper | P1 | Phase1 | 6-Dec-13 | 0.6 |
| 2 | CTR08 | Oper | P1 | Phase1 | 6-Dec-13 | 0.6 |
| 3 | CTR07 | Risk | P1 | Phase1 | 13-Dec-13 | 0.6 |
| 3 | CTR07 | Risk | P1 | Phase1 | 13-Dec-13 | 0.6 |
| 3 | CTR07 | Risk | P1 | Phase1 | 13-Dec-13 | 0.6 |
| 3 | CTR08 | Oper | P1 | Phase1 | 13-Dec-13 | 0.9 |
| 3 | CTR08 | Oper | P1 | Phase1 | 13-Dec-13 | 0.9 |
| 3 | CTR08 | Oper | P1 | Phase1 | 13-Dec-13 | 0.9 |
| 4 | CTR07 | Risk | P1 | Phase1 | 20-Dec-13 | 1.1 |
| 4 | CTR07 | Risk | P1 | Phase1 | 20-Dec-13 | 1.1 |
| 4 | CTR07 | Risk | P1 | Phase1 | 20-Dec-13 | 1.1 |
| 4 | CTR08 | Oper | P1 | Phase1 | 20-Dec-13 | 2.7 |
| 4 | CTR08 | Oper | P1 | Phase1 | 20-Dec-13 | 2.7 |
| 4 | CTR08 | Oper | P1 | Phase1 | 20-Dec-13 | 2.7 |
查询:
select
n.n
, b.Code
, b.Desc
, b.Code_0
, b.Desc_0
, T.theDate
, case
when n.n = 1 then `1`
when n.n = 2 then `2`
when n.n = 3 then `3`
when n.n = 4 then `4`
/* when n.n = 5 then `5` */
/* when n.n = 50 then `50`*/
end as Percentage
from BadTable as B
cross join (select N from TransPoser where N < 5) as N
inner join (
/* transpose just the date row */
/* join back vis the number given to each row */
select
n.n
, case
when n.n = 1 then `1`
when n.n = 2 then `2`
when n.n = 3 then `3`
when n.n = 4 then `4`
/* when n.n = 5 then `5` */
/* when n.n = 50 then `50`*/
end as theDate
from BadTable as B
cross join (select N from TransPoser where N < 5) as N
where b.code is null
and b.Period = 'Date'
) as T on N.N = T.N
where b.code is NOT null
and b.Period <> 'Date'
order by
n.n
, b.code
;
由于问题恕我直言,期待完全准备好的可执行文件可能是不公平的 - 这是“伸展友谊”。但要将上述查询转换为动态查询并不是太难。它只是有点“乏味”,因为语法有点棘手。我对MySQL没有经验,但这就是我要做的事情:
set @numcols := 4;
set @casevar := '';
set @casevar := (
select
group_concat(@casevar
,'when n.n = '
, n.n
,' then `'
, n.n
,'`'
SEPARATOR ' ')
from TransPoser as n
where n.n <= @numcols
)
;
set @sqlvar := concat(
'SELECT n.n , b.Code , b.Desc , b.Code_0 , b.Desc_0 , T.theDate , CASE '
, @casevar
, ' END AS Percentage FROM BadTable AS B CROSS JOIN (SELECT N FROM TransPoser WHERE N <='
, @numcols
, ') AS N INNER JOIN ( SELECT n.n , CASE '
, @casevar
, ' END AS theDate FROM BadTable AS B CROSS JOIN (SELECT N FROM TransPoser WHERE N <='
, @numcols
, ') AS N WHERE b.code IS NULL '
, ' AND b.Period = ''Date'' ) AS T ON N.N = T.N WHERE b.code IS NOT NULL AND b.Period <> ''Date'' ORDER BY n.n , b.code '
);
PREPARE stmt FROM @sqlvar;
EXECUTE stmt;
答案 1 :(得分:0)
一个粗略的方法是:
INFORMATION_SCHEMA.COLUMNS
- 模式或LIKE
ORDINAL_POSITION > 5
中检索列名