我知道那不是问题……反正这就是问题。

我继承了一个数据库,其中包含1(one)表,看起来像这样。 其目的是记录在各个(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)在种类表和国家表中都将具有外键。

(很难绘制图表!)

Species
SpeciesID  SpeciesName

Country
CountryID CountryName

SpeciesFoundInCountry
CountryID SpeciesID

有没有一种神奇的方法可以生成一个插入语句,该语句将根据原始的兆表中的列名和SpeciesID从新的Country表中获取CountryID?

我可以为一个国家/地区做这件事(选择此选项可以显示我想要的东西)

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

(兆表称为物种)

但是使用这种策略,我需要对原始表中的每一列进行查询。

有没有办法在sql中做到这一点?

我想我可以将where子句或一起加载,然后编写脚本来制作sql,虽然看起来不太优雅!

有什么想法(或需要澄清)吗?

===============>>#1 票数:8

为什么要在SQL中执行此操作? 只需编写一个执行转换的小脚本即可。

===============>>#2 票数:8 已采纳

我将使用脚本来生成所有单个查询,因为这是一次性导入过程。

一些程序(例如Excel)擅长混合不同维度的数据(将列名与行内的数据进行比较),而关系数据库很少。

但是,您可能会发现某些系统(令人惊讶的是,例如Microsoft Access)具有方便的工具,可用于标准化数据。 就个人而言,我会发现编写脚本的速度更快,但是您在Access和脚本编写方面的相对技能可能与我有所不同。

===============>>#3 票数:3

当我遇到这些问题时,我写了一个脚本来进行转换,而不是尝试在SQL中进行转换。 对于我来说,它通常更快,更轻松。 选择您喜欢的任何语言。

===============>>#4 票数:2

如果这是SQL Server,则可以使用Unpivot命令,但要查看分配给它的标签以供访问-是吗?

尽管access中有一个关键命令 ,但没有反向语句。

看起来可以通过复杂的连接来完成。 查看这篇有趣的文章,了解有关如何取消选择命令的信息。

===============>>#5 票数:1

如果我不得不创建大量类似的SQL语句并执行所有这些语句,我通常会发现Excel非常方便。 进行原始查询。 如果您在A列中有一个国家/地区列表,而在B列中有您的SQL语句,则格式设置为文本(用引号引起来),并在该国家/地区出现在sql中插入了单元格引用

例如=“ INSERT INTO new_table SELECT ...(species。”&A1&“)= ...));”

然后只需将公式复制下来以创建200个不同的SQL语句,将该列复制/粘贴到您的编辑器中,然后按F5。 当然,您可以根据需要使用多个变量来执行此操作。

===============>>#6 票数:1

(希望如此)这是一项一次性的练习,因此,一个优雅的解决方案可能不会听起来那么糟糕。

问题(例如,我确定您只是太了解了!)是在查询中的某个时刻,您必须列出所有这些列。 :(问题是,最优雅的方法是什么?下面是我的尝试。它看起来很笨拙,因为有很多列,但这可能是您想要的,或者至少它会指出您在正确的方向。

可能的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进行硬编码(因为您只要做一次该操作,对不对?而且您可以在创建了国家/地区表,因此您知道所有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 

===============>>#7 票数:1

当我遇到类似的问题时,我发现生成一个生成SQL脚本的脚本很方便。 这是您提供的示例,被抽象为使用%PAR1%代替阿富汗。

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

此外,还添加了关键字联合作为组合所有选择的一种方式。

接下来,您需要一个根据现有数据生成的国家/地区列表:

阿富汗阿尔巴尼亚。 ,。

接下来,您需要一个可以遍历国家/地区列表的脚本,并且对于每次迭代,都生成一个输出,该输出在第一次迭代中用阿富汗代替%PAR1%,在第二次迭代中用阿尔巴尼亚代替,依此类推。 该算法就像文字处理器中的邮件合并一样。 编写此脚本需要一些工作。 但是,一旦有了它,就可以在数十个这样的一次性项目中使用它。

最后,您需要手动将最后一个“ UNION”改回分号。

如果可以让Access执行此巨型联合,则可以以所需的形式获取所需的数据,并将其插入到新表中。

===============>>#8 票数:1

您可能要在适当的位置创建替换表。 脚本的种类取决于您可用的脚本语言,但是您只需列出当前表中的列就可以创建国家/地区ID表。 完成此操作后,您可以进行一些字符串替换以遍历所有唯一的国家/地区名称,然后插入给定的国家/地区列不为null的speciesFoundInCountry表中。

===============>>#9 票数:1

您可能会变得很聪明,并在系统表中查询列名,然后构建一个动态查询字符串来执行,但是老实说,这可能比为您生成SQL语句的快速脚本更难看。

希望您没有太多动态SQL代码来访问代码库中埋藏的旧表。 那可能是真正困难的部分。

===============>>#10 票数:1

在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' 

===============>>#11 票数:1

与其他人一样,我很可能会以一种适合您的任何方式将其作为一次性快速解决方案。

对于这些类型的转换,它们是一次性的东西,可以快速解决,并且代码不必太优雅,只需要工作即可。 对于这些类型的事情,我已经做了很多方法。

===============>>#12 票数:1

如果是SQL Server,则可以使用sys.columns表查找原始表的所有列。 然后,您可以使用动态SQL和ivot命令执行所需的操作。 在网上查找语法。

===============>>#13 票数:1

我绝对同意您的建议,即编写一个小脚本以对每一列进行查询来生成SQL。

实际上,您的脚本可能已经在您考虑此神奇查询的时间中完成了(您只需使用一次然后扔掉它,那么这一切就变得神奇而完美了有什么用)

===============>>#14 票数:1

我将对您的SpeciesFoundInCountry表进行一些临时修改,使其成为一个三步过程。 我会在该表中添加一列以存储国家/地区名称。 然后,步骤如下。

1)创建/运行一个脚本,该脚本遍历源表中的列,并在SpeciesFoundInCountry中为每个具有真实值的列创建一条记录。 该记录将包含国家名称。 2)运行一条SQL语句,通过加入“国家/地区名称”上的“国家/地区”表来更新SpeciesFoundInCountry.CountryID字段。 3)通过删除CountryName列来清理SpeciesFoundInCountry表。

这是一些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表中的CountryID值。

更新SpeciesFoundInCountry内联接Country on SpeciesFoundInCountry.CountryName = Country.CountryName SET SpeciesFoundInCountry.CountryID = Country.CountryID;

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

****侧面注意:我发现拥有包含ISO缩写(国家/地区代码)的国家/地区表很有用。 有时,它们在其他表中用作外键,因此查询中不必包含与Country表的联接。

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

===============>>#15 票数:1

抱歉,但是流血的发布解析器删除了我发布的空白和格式。 它使日志难以阅读。

===============>>#16 票数:1

@stomp:

在您输入答案的框上方,有几个按钮。 101010是一个代码示例。 您选择所有的代码文本,然后单击该按钮。 这样就不会造成太多混乱。

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

===============>>#17 票数:1

我会非常粗略地使用Union查询:

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

这样,您便可以将视图附加到新设计中。

===============>>#18 票数:1

当我读到标题“ BAD数据库设计不良”时,我很想知道它有多糟糕。 你没有让我失望:)

正如其他人提到的那样,脚本将是最简单的方法。 这可以通过用PHP编写大约15行代码来完成。

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 (...)

显然,这是伪代码,不能按原样工作。 您还可以通过在此处添加插入语句来快速填充国家和物种表。

===============>>#19 票数:1

抱歉,我几乎没有完成Access编程,但是我可以提供一些指南,应该会有所帮助。

首先让我们解决问题。 假定您通常需要在SpeciesFoundInCountry中为原始表中的每一行生成多行。 换句话说,物种往往多于一个国家。 使用笛卡尔积,即没有联接条件的联接,实际上很容易做到。

要执行笛卡尔积,您将需要创建Country表。 该表的country_id应该为1到N(N是唯一国家的数量,大约200个)和国家/地区名称。 为了使生活更轻松,只需按列顺序使用数字1到N。 那将使阿富汗1和阿尔巴尼亚2 ...津巴布韦N。您应该能够使用系统表来执行此操作。

接下来,从原始表创建一个表或视图,其中包含物种和每个国家的0或1的字符串。 您将需要将null而不是null转换为文本0或1,并将所有值连接到单个字符串中。 对表的描述以及带有正则表达式的文本编辑器应该使此操作变得容易。 首先对单个列进行实验,然后进行工作,然后编辑所有列的创建视图/插入。

接下来,将两个表连接在一起,没有连接条件。 这将为您提供每个国家/地区几乎所有物种的记录。

现在,您要做的就是过滤掉无效的记录,它们在字符串的相应位置将为零。 由于国家表的country_code列具有子字符串位置,因此您只需过滤掉0处的记录即可。

where substring(new_column,country_code) = '1'

您仍然需要创建种类表并加入该表

where a.species_name = b.species_name

a和b是表别名。

希望这个帮助

===============>>#20 票数:1

OBTW,

如果查询已经针对旧表运行,则需要创建一个视图,该视图使用新表复制旧表。 您将需要进行分组以对表格进行非规范化。

告诉您的用户,将来将不再支持旧表/视图,并且所有新查询或对旧查询的更新都必须使用新表。

  ask by Loofer translate from so

未解决问题?本站智能推荐:

1回复

设计关系调查问卷数据库

我正在尝试为访问数据库建立一个简单的sql数据库。 目前没有关系,我只有两个表,每个表有6个部分。 如何设计一种更好的方法,以便最终用户可以连接到数据库并使用STATA或SPSS进行分析? 我真的很困惑是应该创建一个包含所有字段的表还是分解成不同的表。 该数据库仅适用于本研究,因此
1回复

链接和添加列到数据库表的简单正确方法,数据库设计

我有下表。 具有以下属性的产品 : ProductID <<产品的ID ProductName <<产品名称 产品价格<<产品价格 具有以下属性的配方 : RecipeID <<配方索引 P
2回复

具有不同层次结构要存储的数据库设计问题

我的数据库设计有一个小问题。 我不必用不同的公司层次结构来解决问题,我必须照顾和存储这些信息。 我正在尝试建立一个数据库,该数据库可以存储有关我已经联系或将要联系的人的信息。 我还需要存储有关特定人员工作的公司的详细信息。 问题在于公司具有不同的结构。 如果我考虑某人工作的学术角色,那
1回复

如何设计Access数据库表,其中只有两个字段之一将具有数据?

我正在创建一个Access数据库,其中包含一个与ITEMS表相关的SALES表,其中包含已购买的服务和用品。 ITEMS表中的每个记录都将具有供应或服务名称,它们各自在各自的表中包含定价和相关信息。 如何在Access中创建此ITEMS表,以使每个记录的两个字段之一为空? 查询此表时会产生
5回复

子类型化数据库表

在设计数据库时,我听到很多关于子表格的说法,我完全了解它们背​​后的理论。 但是,我从未真正看到表格子类型在行动。 如何创建表的子类型? 我正在使用MS Access,我正在寻找一种在SQL和GUI(Access 2003)中实现它的方法。 干杯!
2回复

Access数据库规范化

我目前正在尝试规范化现有数据库。 我的问题类似于此视频http://youtu.be/4q-keGvUnag?t=5m1s中大约5分钟的问题。 他说不做的事情(对于有两名作者的书有两列)是我的数据库存在的问题。 我想知道查询是否可以修改表,使其仅具有一个作者列,并且每个作者都具有单独的
1回复

在Access数据库表中的字段名称中破折号

我在从ms-access数据库检索字段时遇到问题。 表名称为TEST,字段名称之一为HD-TEST 当我做: 选择*从TEST.HD-TEST ='H'的TEST中,我执行查询,ms-access向我显示一个对话框,要求输入参数HD。 你知道可能是什么原因吗? 非常
4回复

数据库规范化问题

我刚刚开始学习有关数据库规范化的问题,并且对一个表有疑问。 我的数据库现在结构很糟,原因之一是因为我有一个像这样的表。 客户表 ... ... 。 由于我的公司从多个来源获取地址数据,因此地址一直在不断增加。 但是,当然,对于某些客户而言,其中一些地址将为
2回复

该数据库的结构应该是什么? [关闭]

我想知道数据库的结构以及结构。 我很困惑我应该如何工作。 它基本上是针对汽车设计的。 要求:1)组装很多。 2)在一个特定的装配体中,有很多零件。 3)在特定部分中可以有“材料”,“过程”,“紧固件”,“工装”表。 它描述了什么以及如何制造零件。 4)材料,工艺,紧固件,模
1回复

具有过多缺勤警报的考勤数据库

我有一个非常标准的考勤数据库设计,但我想在学生遇到一定数量的缺席时收到警报。 我正在考虑使用一个点系统,每个缺席会积累一定数量的点(在学生表本身上跟踪),它会抛出一条消息。 该数据库目前在Access 2003中,但我可能会在不久的将来将其转移到MS SQL Server。 这是我的设