我知道,这不是一个问题...呃无论如何这是个问题。

我继承了一个数据库,有1(一)表在这看起来就像这个。其目的是记录是什么品种在各种(200奇怪的)国家。

ID 
Species
Afghanistan
Albania
Algeria
American Samoa
Andorra
Angola
....
Western Sahara
Yemen
Zambia
Zimbabwe

一个样本数据就是像这样的东西

id Species Afghanistan Albania American Samoa
1  SP1         null     null        null
2  SP2          1         1         null
3  SP3         null      null         1

在我看来这是一个典型的许多许多情况下,我想3的表格。物种、国家和SpeciesFoundInCountry

链接表(SpeciesFoundInCountry)将外键,在这两个物种和国家表。

(这是很难画的图!)

Species
SpeciesID  SpeciesName

Country
CountryID CountryName

SpeciesFoundInCountry
CountryID SpeciesID

是否有一个魔术我可以产生的一个插入语句,将得到了从新的国家表的基础上的列名和SpeciesID有1在原来的大型的表?

我可以做它为一个国家(这是一个选择,以显示我想要什么了)

SELECT Species.ID, Country.CountryID
FROM Country, Species
WHERE (((Species.Afghanistan)=1)) AND (((Country.Country)="Afghanistan"));

(兆表被称为种类)

但使用这种策略,我需要做的查询每一列在原表。

是有这样做的一种方法在sql?

我想我可以载我在那里的条款在一起,并编写脚本,使sql,似乎不优雅的,但!

任何思想(或澄清要求的)?

有帮助吗?

解决方案

我会用一个脚本生成的所有个人查询,因为这是一个关闭的进程。

一些程序,例如Excel是在混合的不同方面的数据(比较的列名数据的内部行),但是关系数据库的数据很少。

但是,你可能会发现一些系统(例如,Microsoft访问,令人吃惊的是)有方便的工具,可以使用正常化的数据。我个人会发现它更快地编写脚本,但你的相对能力与获取和脚本可能不同于我的。

其他提示

为什么你想要做SQL?只写了一个小小的脚本的转换。

当我遇到这些我写的脚本来做转换而不是试图做到这一点在SQL。这是通常更快和更容易对我来说。选择任何语言,你是舒服。

如果这是SQL服务器上,使用逆透视命令,但看着标签的你分配给它的访问-是吗?

虽然有一个 枢命令在访问, 没有逆转发言。

看起来像它可以做一个复杂的加入。检查这个 有趣的文章 一内幕就如何逆透视在一个选择的命令。

你可能会想要创造替代表。脚本排序取决于脚本语言提供给你,但你应该能够创建的国家ID表简单地通过清单所列的表格你现在有。一旦你做了,你可以做一些串替代通过的所有的独特的国家的名字,并插入speciesFoundInCountry表在给定国家列不是空。

你很可能获得聪明和查询系统表的列名,然后建立一个动态查询串到执行,但是说实话这可能会更丑比快脚本生成的SQL报表。

希望你没有太多动态SQL代码的访问旧表埋在你的代码。那可能是 真的 困难的部分。

在SQL Server这将生成定制选择你证明。你可以推断,插入

select 
  'SELECT Species.ID, Country.CountryID FROM Country, Species WHERE (((Species.' + 
 c.name + 
 ')=1)) AND (((Country.Country)="' +
 c.name + 
 '"))'
from syscolumns c
inner join sysobjects o
on o.id = c.id
where o.name = 'old_table_name'

与其他人我会很可能只是做它作为一个时间了速战速决,不论以何种方式对你的作品。

与这些类型的转换,他们是一个关闭的项目,快速修复,以及代码没有被优雅的,它只是有工作。对于这些类型的事情我做了很多种方法。

如果这是SQL服务器,可以使用sys.列表查找所有的列的原始表格。然后你就可以使用动态SQL和枢轴命令去做你想要什么。看看这些了在线语法。

我肯定会同意你的建议编写一个小脚本生产SQL有查询每一个柱。

事实上你的剧本可能已经完成的时间,你已经花了思考有关这个神奇的查询(即你将只使用一个时间,然后扔掉,所以有什么用它的所有magicy和完美)

对不起,但是血腥的张贴分析器拆除的空白和格式在我的职务。它使一个记录难以阅读。

@跺:

上述的框类型的回答,有几个按钮。一个是101010是一种代码样本。你选择了你所有的案文是代码,然后点击按钮。然后它没有得到搞砸了多。

cout>>"I don't know C"
cout>>"Hello World"

我会用一个联合查询,很大致为:

Dim db As Database
Dim tdf As TableDef

Set db = CurrentDb

Set tdf = db.TableDefs("SO")

strSQL = "SELECT ID, Species, """ & tdf.Fields(2).Name _
    & """ AS Country, [" & tdf.Fields(2).Name & "] AS CountryValue FROM SO "

For i = 3 To tdf.Fields.Count - 1
    strSQL = strSQL & vbCrLf & "UNION SELECT ID, Species, """ & tdf.Fields(i).Name _
    & """ AS Country, [" & tdf.Fields(i).Name & "] AS CountryValue FROM SO "
Next

db.CreateQueryDef "UnionSO", strSQL

你会再有一个认为,可以附加于你新的设计。

当我阅读标题'的坏坏的数据库的设计,我很好奇,想找出这是多么糟糕。你没有让我失望:)

正如其他人所述,一个脚本将是最简单的方法。这可以通过编写大约15行代码在PHP.

SELECT * FROM ugly_table;
while(row)
foreach(row as field => value)
if(value == 1)
SELECT country_id from country_table WHERE country_name = field;

if(field == 'Species')
SELECT species_id from species_table WHERE species_name = value;

INSERT INTO better_table (...)

很明显,这是伪代码并不会的工作,因为它是。你也可以填充的国家和种表在飞行中加入语句插在这里。

对不起,我已经做了很少的访问的编程,但我可以提供一些指导,它应该有所帮助。

首先让我们步行通过的问题。假设你会通常需要产生多行SpeciesFoundInCountry中的每一行的原始表格。换句话说物种往往是在一个以上的国家。这实际上是很容易做到的有笛卡尔的产品,与没有加入标准。

做一个笛卡尔的产品则需要创建国家表。该表应有country_id从1到N(N号的独特的国家、200或使)和国家的名称。让生活轻松只是使用数字1到N列顺序。这将使阿富汗1和阿尔巴尼亚的2...N.津巴布韦你应该能够使用的系统表做到这一点。

接下来,创建一个表格或图从原来的表,其中包含的种类和刺用0或1对每个国家。你会需要转换null,"not null"一文本0或1和连接所有的价值观纳入一个单一串。一个说明表和一个文本编辑器与常规的表情应该让这个容易的。实验的第一个单列和一旦工作编辑创建图/插入与所有列。

下一个加入两个表一起,与没有加入标准。这会给你一个记录每个物种在每一个国家,你们几乎没有。

现在,你所需要做的就是过滤出来的记录是无效的,他们将有一个零,在相应的位置。由于该国表的country_code列有substring位置的所有您需要做的只是筛选出记录,它是0.

where substring(new_column,country_code) = '1'

你将仍然需要创建一种表和加入,

where a.species_name = b.species_name

a和b都表的别名。

希望这个帮助

OBTW,

如果你有的查询已经运行针对老表,你将需要创建一个图,这次重复老表,使用新表格。你需要做一组由非规范化的表格。

告诉你的用户,老表/图将不支持在未来的所有新的查询或更新旧的查询将使用新表格。

如果我必须创建一卡车的类似SQL的发言和执行所有这些,我经常发现Excel是非常方便。把你原来的查询。如果你有一个国家名单列一个和你SQL声明中列B、格式化作为文本(报价)的细胞引用插那里的国家出现在sql

例如="INSERT INTO new_table选择...(种类。" &A1&")=...));"

然后只是复制式下创建200种不同的SQL声明、复制、粘贴列为你的编辑打F5。你当然可以这样做因为许多变量,如要你想。

当我一直面临着类似的问题,我已经找到了方便产生一个脚本生成SQL脚本。这样你给抽象使用%PAR1%,在地方的阿富汗。

SELECT Species.ID, Country.CountryID
FROM Country, Species
WHERE (((Species.%PAR1%)=1)) AND (((Country.Country)="%PAR1%"))
UNION

还关键词盟已经加入作为一种方式,结合所有的选择。

接下来,你需要一个名单的国家,从产生的现有数据:

阿富汗 阿尔巴尼亚 ., .

下次你需要一个剧本,可以通过循环访问的国家名单,并且为每次迭代, 产生输出,替代阿富汗%PAR1%上第一次迭代,阿尔巴尼亚的第二次迭代。的算法是,就像邮件合并在文字处理器。这是一个小的工作编写的这个剧本。但是,一旦你有了它,你可以用它在几十个像这样的项目之一。

最后,你需要手动改变的最后的"联盟"回到一分号。

如果你可以获得执行这个巨大的联盟,可以得到你想要的数据的形式要你想,并插入新的表格。

我会让它三个步骤的过程,与一个微小的临时修改,以你的SpeciesFoundInCountry表。我想添加一栏,表以储存的国家的名称。然后的步骤如下。

1)创建/运行一个脚本走列在来源表,并创建一个记录在SpeciesFoundInCountry每一列有一个真正的价值。这一记录将包含国家的名称。2)Run a SQL的发言,更新的SpeciesFoundInCountry.了场通过加入该国表国家的名称。3)清理SpeciesFoundInCountry表通过删除CountryName列。

这里是一个小MS Access VB/VBA伪码给你的要点

Public Sub CreateRelationshipRecords()

  Dim rstSource as DAO.Recordset
  Dim rstDestination as DAO.Recordset
  Dim fld as DAO.Field
  dim strSQL as String
  Dim lngSpeciesID as Long

  strSQL = "SELECT * FROM [ORIGINALTABLE]"
  Set rstSource = CurrentDB.OpenRecordset(strSQL)
  set rstDestination = CurrentDB.OpenRecordset("SpeciesFoundInCountry")

  rstSource.MoveFirst

  ' Step through each record in the original table
  Do Until rstSource.EOF
    lngSpeciesID = rstSource.ID
    ' Now step through the fields(columns). If the field
    ' value is one (1), then create a relationship record
    ' using the field name as the Country Name
    For Each fld in rstSource.Fields
      If fld.Value = 1 then
        with rstDestination
          .AddNew
          .Fields("CountryID").Value = Null
          .Fields("CountryName").Value = fld.Name
          .Fields("SpeciesID").Value = lngSpeciesID
          .Update
        End With
      End IF
    Next fld  
    rstSource.MoveNext
  Loop

  ' Clean up
  rstSource.Close
  Set rstSource = nothing
  ....

End Sub

在此之后,你可以跑一个简单的SQL声明更新了值SpeciesFoundInCountry表。

更新SpeciesFoundInCountry内加入的国家SpeciesFoundInCountry.CountryName=的国家。CountryName组SpeciesFoundInCountry.了=的国家。了;

最后,你所要做的就是清理SpeciesFoundInCountry表通过删除CountryName列。

****侧注意:我已经找到了有用的,有国家表,也包括ISO缩写(国家代码)。有时它们被用来作为外键的其他表中,以便加入到国家表没有被包括在查询。

更多信息: http://en.wikipedia.org/wiki/Iso_country_codes

这是(希望)的一个运动,因此,一个不优雅的解决方案可能不是那么糟糕,因为它的声音。

问题(如,我敢肯定你只是太知道!) 是的,在某些时候在查询你要列出所有这些列。:(现在的问题是,什么是最优雅的方式做到这一点?下面是我的尝试。它看上去笨拙,因为有这么多柱,但它可能是什么你之后,或至少它可能意你在正确的方向。

可能SQL解决方案:

/* if you have N countries */
CREATE TABLE Country
(id    int, 
 name  varchar(50)) 

INSERT Country
      SELECT 1, 'Afghanistan'
UNION SELECT 2, 'Albania', 
UNION SELECT 3, 'Algeria' ,
UNION SELECT 4, 'American Samoa' ,
UNION SELECT 5, 'Andorra' ,
UNION SELECT 6, 'Angola' ,
...
UNION SELECT N-3, 'Western Sahara', 
UNION SELECT N-2, 'Yemen', 
UNION SELECT N-1, 'Zambia', 
UNION SELECT N, 'Zimbabwe', 



CREATE TABLE #tmp
(key        varchar(N),  
 country_id int) 
/* "key" field needs to be as long as N */  


INSERT #tmp 
SELECT '1________ ... _', 'Afghanistan' 
/* '1' followed by underscores to make the length = N */

UNION SELECT '_1_______ ... ___', 'Albania'
UNION SELECT '__1______ ... ___', 'Algeria'
...
UNION SELECT '________ ... _1_', 'Zambia'
UNION SELECT '________ ... __1', 'Zimbabwe'

CREATE TABLE new_table
(country_id int, 
species_id int) 

INSERT new_table
SELECT species.id, country_id
FROM   species s , 
       #tmp    t
WHERE  isnull( s.Afghanistan, ' ' ) +  
       isnull( s.Albania, ' ' ) +  
       ... +  
       isnull( s.Zambia, ' ' ) +  
       isnull( s.Zimbabwe, ' ' ) like t.key 

我的建议

就个人而言,我不会这么做。我会做一个快速解决方案一样,其暗示,除了我的硬代码的国家标识(因为你只要做到这一次,对吗?你可以做到这一点之后,你创建的国家表,所以你知道什么所有的Id):

INSERT new_table SELECT Species.ID, 1 FROM Species WHERE Species.Afghanistan = 1 
INSERT new_table SELECT Species.ID, 2 FROM Species WHERE Species.Albania= 1 
...
INSERT new_table SELECT Species.ID, 999 FROM Species WHERE Species.Zambia= 1 
INSERT new_table SELECT Species.ID, 1000 FROM Species WHERE Species.Zimbabwe= 1 
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top