2014-09-05 2 views
6

파이어 버드 2.1을 사용하고 있습니다. 파이어 버드 세트의 모든 항목과 일치하는 ID를 선택하는 방법

는 테이블 : IDs, Labels

동일한 ID에 대해 여러 레이블이있을 수 있습니다 :

10 Peach 
10 Pear 
10 Apple 
11 Apple 
12 Pear 
13 Peach 
13 Apple 

것은이 전 라벨의 세트를 가지고 있다고 가정 해 봅시다, 즉 : (사과, 배, 복숭아) .

주어진 세트에 모든 레이블이 연결된 모든 ID를 반환하는 단일 선택을 작성하려면 어떻게해야합니까? 가급적이면 쉼표로 구분 된 문자열로 세트를 지정하고 싶습니다. ('Apple', 'Pear', 'Peach') -> ID가 10을 반환해야합니다.

고마워요!

답변

2

질문 : 나는 더 간단한 버전의 piclrow를 게시하고 있습니다. 필자는 Firebird 버전 2.5에서 테스트했으나 OP (Steve)가 2.1에서 테스트를 마쳤습니다.

SELECT id 
FROM table 
WHERE label IN ('Apple', 'Pear', 'Peach') 
GROUP BY id 
HAVING COUNT(DISTINCT label)=3 

이 솔루션은 HAVING = 조건이 상태에서 WHERE 일치해야합니다 당신이, 당신이 찾고있는 얼마나 많은 값을 알 필요가 ... 단락 기호의 같은 단점이있다. 이 점에서 Ed의 대답은 연결된 값 문자열 매개 변수를 분할하고 값을 계산하므로보다 유연합니다. 따라서 필자가 사용하는 2 가지 조건 대신에 하나의 매개 변수 만 변경하면됩니다.

OTOH, 효율성이 걱정된다면 필자는 Ed의 CTE 접근 방식이 Firebird 엔진에 의해 제안 된 것보다 덜 최적화 될 수 있다고 생각합니다 (그러나 나는 절대적으로 확신하지 못합니다). 파이어 버드는 쿼리를 최적화하는 데 아주 능숙하지만 CTE를 사용할 때 이렇게 할 수 있다면 지금은 그렇지 않습니다. 그러나 WHERE + GROUP BY + HAVING은 단순히 (id, label)에 색인을 붙임으로써 최적화 될 수 있어야합니다.

+0

귀하의 (또는 pilcrow 's) 쿼리에 CTE ("공통 테이블 식")이 없습니다 –

+0

그 의견은 Ed의 답변에 언급되었지만 훌륭하고 융통성이 있지만 ** CTE를 사용합니다 **. 나는 그것을 더 명확하게 할 것이다.감사합니다 – Frazz

+0

너무 FB2.1와 함께 작동합니다. 이것이 가장 간단한 쿼리이기 때문에 이것을 대답으로 삼을 것입니다. 감사! – Steve

2

그것은 코드에서 문자열을 분할하고 그 다음 다음 사항을 고려 선택 차에서 호출되는 도우미 저장 프로 시저를 만들 허용의 경우,

SQL> select ID 
CON> from (select ID, count(DISTINCT LABEL) as N_LABELS 
CON>   from T 
CON>   where LABEL in ('Apple', 'Pear', 'Peach') 
CON>   group by 1) D 
CON> where D.N_LABELS >= 3; -- We know a priori we have 3 LABELs 

      ID 
============ 
      10 
+1

은 무엇 경우 (ID, 라벨) 고유하지 않습니다), 실행 시간이 귀하의 경우 문제의 경우 사용자가 선택 중 솔루션

결론적으로, 당신은 아마 무슨 일이 일어나고 있는지 볼 수있는 몇 가지 설명 할 계획이 필요하십니까? subselect에 DISTINCT를 추가 할 것입니다. 다만 ...) – Frazz

+0

@Frazz, 예, 고맙습니다. – pilcrow

+0

필자는 Firebird를 한동안 사용하지 않았으며이 유형의 쿼리를 수행하는 데 Firebird를 사용하지 않았습니다. Firebird의 SUBSELECT 없이는이 작업을 수행 할 수 없습니까? 내 말은 ... 바깥 쪽을 선택하는 대신에 HAVING을 쓰는거야? – Frazz

1

를 조회하는 것이 가장 쉬운 방법이다.

헬퍼 저장 프로 시저가 구분 기호와 함께 구분 된 문자열에 취하고 각각의 구분 된 문자열 아래

CREATE OR ALTER PROCEDURE SPLIT_BY_DELIMTER (
    WHOLESTRING VARCHAR(10000), 
    SEPARATOR VARCHAR(10)) 
RETURNS (
    ROWID INTEGER, 
    DATA VARCHAR(10000)) 
AS 
DECLARE VARIABLE I INTEGER; 
BEGIN 
    I = 1; 
    WHILE (POSITION(:SEPARATOR IN WHOLESTRING) > 0) DO 
    BEGIN 
     ROWID = I; 
     DATA = TRIM(SUBSTRING(WHOLESTRING FROM 1 FOR POSITION(TRIM(SEPARATOR) IN WHOLESTRING) - 1));   
     SUSPEND;  
     I = I + 1; 
     WHOLESTRING = TRIM(SUBSTRING(WHOLESTRING FROM POSITION(TRIM(SEPARATOR) IN WHOLESTRING) + 1)); 
    END 
    IF (CHAR_LENGTH(WHOLESTRING) > 0) THEN 
    BEGIN 
     ROWID = I; 
     DATA = WHOLESTRING; 
     SUSPEND; 
    END 
END 

호출하는 코드가에 대한 행을 반환

, 나는 구분 전달 입증하기 위해 블록을 실행 사용하고 있습니다 문자열

EXECUTE BLOCK 
RETURNS (
    LABEL_ID INTEGER) 
AS 
DECLARE VARIABLE PARAMETERS VARCHAR(50); 
BEGIN 
    PARAMETERS = 'Apple,Peach,Pear'; 

    FOR WITH CTE 
    AS (SELECT ROWID, 
      DATA 
     FROM SPLIT_BY_DELIMITER(:PARAMETERS, ',')) 
    SELECT ID 
    FROM TABLE1 
    WHERE LABELS IN (SELECT DATA 
        FROM CTE) 
    GROUP BY ID 
    HAVING COUNT(*) = (SELECT COUNT(*) 
        FROM CTE) 
    INTO :LABEL_ID 
    DO 
    SUSPEND; 
END