各种(200多个)国家。
ID种类阿富汗阿尔巴尼亚阿尔及利亚美属萨摩亚安道尔安哥拉….西 撒哈拉 </跨度> 也门赞比亚津巴布韦
数据的样本将是这样的
当我遇到这些时,我编写了一个脚本来进行转换,而不是尝试在SQL中执行。对我来说,它通常更快更容易。选择您喜欢的任何语言。
如果我必须创建一堆类似的SQL语句并执行所有这些语句,我经常发现Excel非常方便。采取原始查询。如果您在A列中有一个国家/地区列表,而在B列中有您的SQL语句,则将其格式化为文本(在引号中),并在sql中插入单元格引用
例如=“INSERT INTO new_table SELECT ...(species。”&amp; A1&amp;“)= ...));”
然后只需复制公式以创建200个不同的SQL语句,将列复制/粘贴到编辑器并按F5。当然,您可以根据需要使用尽可能多的变量来执行此操作。
您可能想要创建替换表。脚本类型取决于您可以使用的脚本语言,但您应该只需列出您现在拥有的表的列就可以创建国家/地区ID表。完成后,您可以执行一些字符串替换以遍历所有唯一的国家/地区名称,并插入到itemsFoundInCountry表中,其中给定的国家/地区列不为空。
当我读到“糟糕的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 (...)
显然这是伪代码,不会像现在这样工作。您还可以通过在此处添加插入语句来动态填充国家/地区和物种表。
在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脚本的脚本很方便。这是你提供的样本,抽象使用%PAR1%代替阿富汗。
SELECT Species.ID, Country.CountryID FROM Country, Species WHERE (((Species.%PAR1%)=1)) AND (((Country.Country)="%PAR1%")) UNION
此外,关键词union已被添加为组合所有选择的一种方式。
接下来,您需要一个根据现有数据生成的国家/地区列表:
阿富汗 阿尔巴尼亚 。 , 。
接下来,您需要一个可以遍历国家/地区列表的脚本,并且对于每次迭代, 产生一个输出,在第一次迭代时替代阿富汗%PAR1%,在第二次迭代时替代阿尔巴尼亚,依此类推。该算法就像文字处理器中的邮件合并一样。编写这个脚本有点工作。但是,一旦你拥有它,你可以在像这样的几十个一次性项目中使用它。
最后,您需要手动将最后一个“UNION”更改回分号。
如果您可以使用Access来执行此巨型联合,则可以以所需的形式获取所需的数据,并将其插入新表中。
如果这是SQL Server,则可以使用sys.columns表查找原始表的所有列。然后,您可以使用动态SQL和pivot命令来执行您想要的操作。查看那些在线的语法。
您可能会聪明地查询系统表中的列名,然后构建一个动态查询字符串来执行,但老实说,这可能比快速脚本更难以为您生成SQL语句。
希望您没有太多动态SQL代码来访问隐藏在代码库中的旧表。那可能是 真 困难的部分。
和其他人一样,我很可能会以任何适合你的方式快速修复它。
通过这些类型的转换,它们是一个关闭的项目,快速修复,并且代码不必是优雅的,它只需要工作。对于这些类型的事情,我已经做了很多方面。
OBTW,
如果您有针对旧表运行的查询,则需要创建一个使用新表复制旧表的视图。您需要执行一个组来对表进行非规范化。
告诉您的用户将来不支持旧表/视图,所有新查询或旧查询的更新都必须使用新表。
我会通过对您的SpeciesFoundInCountry表进行轻微的临时修改来实现它的三步过程。我会在该表中添加一列来存储国家/地区名称。然后步骤如下。
1)创建/运行一个脚本,该脚本遍历源表中的列,并在SpeciesFoundInCountry中为每个具有true值的列创建记录。此记录将包含国家/地区名称。 2)运行SQL语句,通过加入Country Name上的Country表来更新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值。
UPDATE SpeciesFoundInCountry INNER JOIN Country ON SpeciesFoundInCountry.CountryName = Country.CountryName SET SpeciesFoundInCountry.CountryID = Country.CountryID;
最后,您所要做的就是通过删除CountryName列来清理SpeciesFoundInCountry表。
**** SIDE注意:我发现让国家/地区表格也包含ISO缩写(国家/地区代码)非常有用。有时,它们在其他表中用作外键,因此不必在查询中包含到Country表的连接。
欲了解更多信息: http://en.wikipedia.org/wiki/Iso_country_codes
我会使用脚本生成所有单个查询,因为这是一次性导入过程。
某些程序(如Excel)擅长混合不同维度的数据(将列名与行内数据进行比较),但关系数据库很少。
但是,您可能会发现某些系统(例如Microsoft Access,令人惊讶)具有可用于规范化数据的便捷工具。就个人而言,我发现编写脚本的速度更快,但是你使用Access和脚本编写的相关技能可能与我的不同。
如果这是SQL Server,您将使用Unpivot命令,但查看您为其分配的标记以供访问 - 我是对的吗?
虽然有一个 访问中的枢轴命令 ,没有反向声明。
看起来可以通过复杂的连接来完成。检查一下 有趣的文章 关于如何在select命令中取消忽略的问题。
为什么要在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
我会使用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
然后,您将拥有一个可以附加到新设计的视图。
@stomp:
在您键入答案的框上方,有几个按钮。 101010是代码示例。您选择所有代码文本,然后单击该按钮。然后它不会搞砸太多。
cout>>"I don't know C" cout>>"Hello World"