문제

나는 그것이 질문이 아니라는 것을 알고 있습니다 ...음 어쨌든 질문은 여기 있습니다.

나는 이와 유사한 테이블이 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

원래 메가 테이블에 1이 있는 SpeciesID와 열 이름을 기반으로 새 Country 테이블에서 CountryID를 가져오는 삽입 문을 생성할 수 있는 마법의 방법이 있습니까?

한 국가에 대해 할 수 있습니다(이것은 내가 원하는 것을 보여주기 위한 선택입니다).

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

(메가 테이블을 종이라고 합니다)

하지만 이 전략을 사용하면 원본 테이블의 각 열에 대해 쿼리를 수행해야 합니다.

SQL에서 이것을 수행하는 방법이 있습니까?

나는 OR 절을 함께 로드하고 SQL을 만들기 위한 스크립트를 작성할 수 있다고 생각하지만 우아하지 않은 것 같습니다!

어떤 생각(또는 설명이 필요함)이 있습니까?

도움이 되었습니까?

해결책

이는 일회성 가져오기 프로세스이므로 스크립트를 사용하여 모든 개별 쿼리를 생성하겠습니다.

Excel과 같은 일부 프로그램은 다양한 차원의 데이터를 혼합하는 데 능숙하지만(열 이름을 행 내부의 데이터와 비교) 관계형 데이터베이스는 거의 그렇지 않습니다.

그러나 일부 시스템(예: 놀랍게도 Microsoft Access)에는 데이터를 정규화하는 데 사용할 수 있는 편리한 도구가 있다는 것을 알 수 있습니다.개인적으로 나는 스크립트를 작성하는 것이 더 빠르다고 생각하지만 액세스 및 스크립팅에 대한 상대적인 기술은 나와 다를 수 있습니다.

다른 팁

왜 SQL로 하려고 합니까?변환을 수행하는 작은 스크립트를 작성하십시오.

이러한 문제가 발생하면 SQL에서 변환을 시도하는 대신 변환을 수행하는 스크립트를 작성합니다.일반적으로 나에게는 훨씬 빠르고 쉽습니다.편안하게 사용할 수 있는 언어를 선택하세요.

이것이 SQL Server라면 Unpivot 명령을 사용하겠지만 할당한 태그를 보면 액세스용입니다. 맞나요?

비록 액세스 중 피벗 명령, 반대 진술은 없습니다.

복잡한 조인으로 수행할 수 있는 것 같습니다.이것을 확인하세요 흥미로운 기사 선택 명령에서 피벗을 해제하는 방법에 대해 자세히 알아보세요.

아마도 대체 테이블을 그 자리에 생성하고 싶을 것입니다.스크립트 종류는 사용 가능한 스크립트 언어에 따라 다르지만 현재 가지고 있는 테이블의 열을 나열하는 것만으로 국가 ID 테이블을 만들 수 있습니다.그런 다음 문자열 대체를 수행하여 모든 고유 국가 이름을 살펴보고 해당 국가 열이 null이 아닌 종FoundInCountry 테이블에 삽입할 수 있습니다.

아마도 영리하게 시스템 테이블에서 열 이름을 쿼리한 다음 실행할 동적 쿼리 문자열을 작성할 수 있지만 솔직히 그것은 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 Server인 경우 sys.columns 테이블을 사용하여 원본 테이블의 모든 열을 찾을 수 있습니다.그런 다음 동적 SQL과 피벗 명령을 사용하여 원하는 작업을 수행할 수 있습니다.구문은 온라인에서 찾아보세요.

나는 모든 열에 대한 쿼리를 사용하여 SQL을 생성하는 작은 스크립트를 작성하라는 귀하의 제안에 확실히 동의합니다.

사실 이 마법 같은 쿼리(한 번만 사용하고 버리면 모든 것을 마법처럼 완벽하게 만드는 데 무슨 소용이 있겠습니까?)에 대해 생각한 시간에 스크립트가 이미 완료되었을 수도 있습니다.

죄송합니다. 빌어먹을 게시 파서가 내 게시물의 공백과 서식을 제거했습니다.로그를 읽기 어렵게 만듭니다.

@스톰프:

답변을 입력하는 상자 위에는 여러 개의 버튼이 있습니다.101010은 코드 샘플입니다.코드인 텍스트를 모두 선택한 다음 해당 버튼을 클릭합니다.그러면 별로 망가지지 않습니다.

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

대략적으로 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

그러면 새 디자인에 추가할 수 있는 뷰가 생성됩니다.

'Bad BAD Database Design'이라는 제목을 읽었을 때 얼마나 나쁜지 궁금했습니다.당신은 나를 실망시키지 않았습니다 :)

다른 사람들이 언급했듯이 스크립트가 가장 쉬운 방법입니다.이는 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 (...)

분명히 이것은 의사 코드이므로 그대로 작동하지 않습니다.여기에 삽입 문을 추가하여 즉시 국가 및 종 테이블을 채울 수도 있습니다.

죄송합니다. 저는 Access 프로그래밍을 거의 하지 않았지만 도움이 될 만한 몇 가지 지침을 제공할 수 있습니다.

먼저 문제를 살펴보겠습니다.일반적으로 원래 테이블의 모든 행에 대해 SpeciesFoundInCountry에서 여러 행을 생성해야 한다고 가정합니다.즉, 종은 한 국가 이상에 존재하는 경향이 있습니다.이는 조인 기준이 없는 조인인 데카르트 곱을 사용하면 실제로 쉽게 수행할 수 있습니다.

데카르트 곱을 수행하려면 국가 테이블을 만들어야 합니다.테이블에는 1부터 N까지의 country_id(N은 고유 국가 수, 200 정도)와 국가 이름이 있어야 합니다.쉽게 사용하려면 1부터 N까지의 숫자를 열 순서대로 사용하세요.그러면 아프가니스탄 1과 알바니아 2가...짐바브웨 N.이를 수행하려면 시스템 테이블을 사용할 수 있어야 합니다.

다음으로 각 국가에 대해 0 또는 1이 있는 종과 찌르기를 포함하는 원본 테이블에서 테이블 또는 뷰를 만듭니다.null이 아닌 null을 텍스트 0 또는 1로 변환하고 모든 값을 단일 문자열로 연결해야 합니다.테이블에 대한 설명과 정규 표현식이 포함된 텍스트 편집기를 사용하면 이 작업이 쉬워집니다.먼저 단일 열로 실험하고 일단 작동되면 모든 열이 포함된 보기/삽입 만들기를 편집하세요.

다음으로 조인 기준 없이 두 테이블을 조인합니다.이것은 모든 국가의 모든 종에 대한 기록을 제공할 것입니다. 거의 다 왔습니다.

이제 당신이 해야 할 일은 유효하지 않은 레코드를 필터링하는 것뿐입니다. 문자열의 해당 위치에 0이 있을 것입니다.국가 테이블의 country_code 열에는 하위 문자열 위치가 있으므로 해당 위치가 0인 레코드를 필터링하기만 하면 됩니다.

where substring(new_column,country_code) = '1'

여전히 종 테이블을 생성하고 이에 조인해야 합니다.

where a.species_name = b.species_name

a와 b는 테이블 별칭입니다.

이 도움을 바랍니다

OBTW,

이전 테이블에 대해 이미 실행된 쿼리가 있는 경우 새 테이블을 사용하여 이전 테이블을 복제하는 뷰를 만들어야 합니다.테이블을 비정규화하려면 그룹화를 수행해야 합니다.

이전 테이블/뷰는 앞으로 지원되지 않으며 모든 새 쿼리 또는 이전 쿼리에 대한 업데이트는 새 테이블을 사용해야 함을 사용자에게 알립니다.

유사한 SQL 문을 트럭 단위로 생성하고 모두 실행해야 하는 경우 Excel이 매우 편리하다는 것을 자주 발견합니다.원래 쿼리를 받아보세요.A 열에 국가 목록이 있고 B 열에 SQL 문이 있는 경우 SQL에서 국가가 나타나는 위치에 셀 참조가 삽입된 텍스트(따옴표)로 형식이 지정됩니다.

예를 들어="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

또한 모든 선택 항목을 결합하는 방법으로 키워드 Union이 추가되었습니다.

다음으로 기존 데이터에서 생성된 국가 목록이 필요합니다.

아프가니스탄 알바니아.,.

다음으로 국가 목록을 통해 반복 할 수있는 스크립트가 필요하며 각 반복마다 아프가니스탄을 첫 번째 반복에서 % PAR1 %로 대체하는 출력, 두 번째 반복 등을 생성합니다.알고리즘은 워드 프로세서의 메일 병합과 같습니다.이 스크립트를 작성하는 것은 약간의 작업입니다.하지만 일단 가지고 있으면 이와 같은 수십 개의 일회성 프로젝트에서 사용할 수 있습니다.

마지막으로 마지막 "UNION"을 다시 세미콜론으로 수동으로 변경해야 합니다.

Access를 통해 이 거대한 통합을 수행할 수 있다면 원하는 형식으로 원하는 데이터를 가져와서 새 테이블에 삽입할 수 있습니다.

SpeciesFoundInCountry 테이블을 일시적으로 약간 수정하여 3단계 프로세스로 만들겠습니다.국가 이름을 저장하기 위해 해당 테이블에 열을 추가하겠습니다.그러면 단계는 다음과 같습니다.

1) 원본 테이블의 열을 탐색하고 True 값이 있는 각 열에 대해 SpeciesFoundInCountry에 레코드를 생성하는 스크립트를 생성/실행합니다.이 레코드에는 국가 이름이 포함됩니다.2) 국가 이름의 국가 테이블에 조인하여 SpeciesFoundInCountry.CountryID 필드를 업데이트하는 SQL 문을 실행합니다.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 국가 ON SpeciesFoundInCountry.CountryName = Country.CountryName SET SpeciesFoundInCountry.CountryID = Country.CountryID;

마지막으로 CountryName 열을 제거하여 SpeciesFoundInCountry 테이블을 정리하기만 하면 됩니다.

****참고사항: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를 하드 코딩하는 것을 제외하고는 당신이 암시하는 것과 같은 빠르고 더러운 솔루션을 수행할 것입니다(왜냐하면 이 작업은 한 번만 수행할 것이기 때문입니다. 그렇죠?그리고 국가 테이블을 생성한 직후에 이를 수행할 수 있으므로 모든 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