2012-11-09 3 views
1

좋습니다. 따라서 카테고리 테이블에 사용 된 4 개의 문자 중 2 개만 포함 된 카테고리 ID 열이 포함 된 제품 테이블에 데이터가 있습니다.SQL에 문제가 있습니다.

예 : 제품에 카테고리 ID 'AA'가 있지만 데스크톱 (AAA) 또는 서버 (AAB) 카테고리 중 하나 일 수 있습니다.

카테고리 테이블에는 우리에게 도움이되는 정보 인 include, atrID 및 valID가 포함 된 3 개의 열이 있습니다. valID 열에는 하나 이상의 ID 만 포함 할 수있는 쉼표로 구분 된 값 목록 (예 : 'K01819'또는 'K00846, K00851')이 들어 있습니다. atrID 열에 유사한 문자열 (예 : 'A00432')이 포함되어 있습니다. 인클루드 컬럼은 오래 전에 프로그래머가 수행 한 작업에 기반하여 1 또는 0 중 하나입니다.

은 기본적으로 그는 다양한 테이블을 통해 저인망 및 특정 범주 (예 : AA)는 우리가 카테고리 테이블에서 다른 테이블에 가입에서 모든 넥타이 valIDs의 atrID 및 목록을 사용할 수 있다는 것을 발견했다.

예 :

제품 "a"는 catID가 AA이고 데스크톱 컴퓨터입니다. 이것은 'AAA'범주에 속하며 포함에 0, atrID에 'A00432'및 valID에 'K01819'가 있습니다.

예 SQL 카테고리 정보를 얻을 수 있습니다 :

SELECT cat.atrID, cat.valID, cat.[include] 
FROM db.dbo.cat AS cat 
WHERE cat.catID = 'AAA' 

그때 닷넷 코드에서 이러한 변수를 저장 등의 값에 따라 SQL을 구축 할 것입니다. 또한 valID를 나눠서 개별 매개 변수로 전달하여 다음 코드가 SQL 서버에서 실행되도록합니다.

SELECT DISTINCT prod.prodID 
FROM db.dbo.prod AS prod 
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID 
WHERE prod.catID = 'AA' 
AND atr.atrID = 'A00432' 
AND atr.valID NOT IN('K01819') 

1. 예제의 포함 값이 나는 서버 (AAB) 같은 INNOT IN을 바꿀 것 서버에 대해이 설정을 변경하려면 :

SELECT DISTINCT prod.prodID 
FROM db.dbo.prod AS prod 
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID 
WHERE prod.catID = 'AA' 
AND atr.atrID = 'A00432' 
AND atr.valID IN('K01819') 
내가 IN 사용

NOT IN을 몇 가지 때문에 카테고리에는 valID 열에 둘 이상의 값이 있습니다.

내 질문에 특정 제품에 대한 카테고리를 이전에 알지 못해도 얻고 싶다면 가능합니까? (귀하가 가지고 있다고 생각하는 카테고리의 모든 제품 목록을 가져 오지 못하거나 하나 또는 다른 목록에서 일치하지 않는 경우). 나는 내 상사에게 지금은 며칠 동안 알아낼 수 없으며 아무데도 못 가고 있다고 말하고있다. 어떤 도움이라도 대단히 감사하겠습니다.

편집 :

난 할 노력하고있어하는 모든 제품에 대한 카테고리를 얻을 수있다. 데스크톱 및 서버 범주에 대한 제품 목록을 얻는 방법의 예로서 위의 SQL을 포함 시켰습니다.

상품 표의 두 글자 카테고리 만있는 경우 카테고리 표에서 3 글자 카테고리를 가져 오는 것과 반대입니다.

편집 2 :

제품 테이블 컬럼 :
PRODID의 VARCHAR (40)
CATID의 문자 (2)

샘플 행 :
'S101010', 'AA'(바탕 화면)
'S202020', 'AA'(서버)
'S303030', 'ED'(레이저 프린터)
'S404040', 'ED'(잉크젯 프린터)

,451,515,

카테고리 테이블 컬럼 :
CATID의 VARCHAR (4)
설명 VARCHAR (50)
비트 (나는 매일 = P에 다루는 것을 보여주기 위해 가야 실제로 TINYINT)
atrID의 VARCHAR (6 포함)
유효한 VARCHAR (250)

샘플 행 :
'AAA', '데스크탑'0 'A00432', 'K01819'
'AAB', '서버'1 'A00432' 'K01819'
'EDA', '레이저 프린터', 1, 'A00172', 'K00846, K00851'
'EDB ","잉크젯 프린터'1 'A00172', 'K00845'

테이블 열 속성 :
PRODID의 VARCHAR (40)
CATID 숯 (2)
atrID의 VARCHAR (10)
을 유효한 VARCHAR (10)

샘플 행 :
'S101010', 'AA', 'A00432', 'K01817'
'S202020', 'AA', 'A00432', 'K01819'
' S303030 ','ED ','A00172 ','K00846 ' 'S303030', 'ED', 'A00172', 'K00851'
'S404040', 'ED', 'A00172', 'K00845'

나는 위의 포함 나가의 목록을 어떻게 무엇을 내가 category.catID를 알고있을 때 제품. 내가 원하는 것은 product.prodID와 product.catID만을 가질 때 카테고리를 얻을 수 있다는 것입니다.

나는 이런 식으로 끝나지만 불완전하고 그대로 작동하지 않습니다. 그런 다음 catIn.catID 및 catNotIn.catID의 결과를 확인하여 어느 것이 null이 아니 었으며 내 범주가 될 것이라고 판단하지만 조인을 파악할 수는 없습니다. 심지어 가능하다면. 또한 두 가지 이상의 변형이있는 범주는 고려하지 않습니다.

SELECT prod.prodID, catIn.catID, catNotIn.catID 
FROM product AS prod 
INNER JOIN attributes AS atr ON atr.prodID = prod.prodID 
LEFT OUTER JOIN category AS catIn ON LEFT(catIn.catID, 2) = prod.catID AND catIn.atrID = atr.atrID --more conditions needed here 
LEFT OUTER JOIN category AS catNotIn ON LEFT(catNotIn.catID, 2) = prod.catID AND catIn.atrID = atr.atrID --more conditions needed here 

나는 이것이 조금 더 나아진 이유를 설명하기를 바랍니다.

+0

잘못된 데이터 정리를 자동화하는 것은 놀라운 일입니다. 카테고리 테이블과 일치시킬 수있는 정보가 제품 테이블에 있어야합니다. prod.catID는 그렇게 지원되었습니다. 그렇게 일치하지 않으면 사용자에게 가능한 모든 일치 항목을 표시하는 화면을 만들어야합니다 (JOIN prod catID AA ON catID LIKE 'AA %'). 가능한 한 쉽게 만들고 사용자가 자신의 잘못된 데이터를 정리하도록하십시오. –

+0

불행히도 그건 옵션이 아닙니다. 우리는 계정 관리자가 자비로 다른 고객을 기반으로 가격을 조정할 수있는 새로운 시스템을 구현하기 때문에이 작업에 참여해야합니다. 카테고리에 대해 마크 업을 지정할 수는 있지만 개별 제품에는 마크 업을 지정할 수 없기 때문에 카테고리를 파악해야하며 고객이 제품을 검색 할 때 계정 관리자가 기대하는 가격과 일치하는지 확인해야합니다. 그것이 덜 사용 빈도가 낮은 범주 일 뿐이라면 데스크탑과 서버처럼 나는 피클에 약간 빠져 있습니다. – Sean

+0

고객 별 마크 업은 별도의 표에 저장해야합니다. 확실히 데이터 모델을 조정해야합니다. products -> product_categories (제품 유형), customers -> customer_categories (고객 유형). 그런 다음 제품 그룹 또는 제품 카테고리별로 고객 그룹에 대한 마크 업을 설정할 수 있도록 product_categories를 customer_categories에 매핑하거나 제품 또는 제품 카테고리별로 특정 고객에 대한 마크 업을 설정해야합니다. 나는 db.dbo.cat이 제품 범주에 속한다고 가정합니다. –

답변

0

데이터 모델이 매우 나쁘다는 말로 시작하겠습니다. 분할하고 일치시켜야하는 곳에 값의 쉼표 목록이 없어야합니다. 그것은 테이블 관계 여야합니다. 하지만 나는 ...유일한 차이점은 내가 이런 짓을 했을까 서버에서 전적으로이 작성한다면 당신은 다음 include의 값에 따라 NOT ININ을 사용할지 여부를 경우

그래서 :

첫째, 자신에게 좋은를 얻을 수 CSV는 UDF를 분할합니다. how to split and insert CSV data into a new table in single statement? 좋은 예입니다. 멋지고 간단합니다. 그런 다음

는, (내가 저장 프로 시저로 변신 것) 쿼리는 것 같이 보일 것입니다 :

CREATE PROCEDURE SprocNameHere 
@prodID INT 
AS 

-- I'm making assumptions about the data types here. Fix them accordingly 
DECLARE @atrID INT 
DECLARE @valID varchar(MAX) 
DECLARE @include BIT 
DECLARE @catID varchar(50) 

-- given the passed in product ID, look up @catID 
SELECT @catID = catID FROM prod WHERE prodID = @prodID 

SELECT @atrID = cat.atrID, @valID = cat.valID, @include = cat.[include] 
FROM db.dbo.cat AS cat 
WHERE cat.catID = @catID 


SELECT DISTINCT prod.prodID 
FROM db.dbo.prod AS prod 
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID 
LEFT JOIN dbo.inline_split_me(',', @valID) ism ON ism.Value = atr.valID 
WHERE prod.catID = 'AA' -- is this hardcoded or should this come from the query above?? How do you convertt 'AAA' to 'AA'? What Table/relationship/concept does this? 
AND atr.atrID = @atrID 
AND ((@include = 0 AND ism.Value IS NULL) OR (@include = 1 AND ism.Value IS NOT NULL)) 

나는 전체를 가지고 있지 않는 한 내 구문은 위의 정확한 확인하기 매우 어려운 작업 모델. 하지만 여기에 일반적인 생각이 있습니다 : 당신의 UDF inline_split_me은 기록을 "테이블"로 나눕니다. LEFT JOIN을 사용하면 atr 테이블 사이에 일치가 없으면 ism.Value는 null이됩니다. 이것을 사용하여 NOT IN을 수행 할 수 있습니다. 시뮬레이션은 IN 시뮬레이션에서도 마찬가지입니다.

편집 1 : 사용자 의견에 따라 다음과 같이 테스트 베드가 있습니다. 나는 데이터에 대한 완전한 시각을 가지고 있지 않지만, 이것이 당신이 찾고있는 것이라고 생각한다. 댓글을 달아서 조정하겠습니다.

샘플 데이터가 주어지면이 데이터를 내 tempdb에서 실행했습니다. EDB에 대한 애트리뷰트 레코드가 없으므로 내가 돌아 오기로되어있는 것을 되찾고 있는지 확신 할 수 없습니다. 또한 Attribute 테이블의 각 valID에 대해 하나씩 두 개의 레코드 S303030이 반환됩니다. ProdID + Category.CatID의 고유성에 대해서만 찾고있는 경우 DISTINCT를 사용하거나 이해할 수없는 퍼즐 조각이있는 경우 알려 주시면 답변을 수정 해 드리겠습니다. 샘플 데이터에 #Category 테이블에 잉크젯 레코드가 없기 때문에이 작업은 잉크젯을 제외한 모든 작업에 적용됩니다. 내가 가짜라고 말하면 UNION SELECT 'S404040', 'ED', 'A00172', 'K00845'이 작동하는 것 같습니다.

--DROP TABLE #Product 
--DROP TABLE #Category 
--DROP TABLE #Attribute 

--DROP FUNCTION inline_split_me 

GO 
CREATE FUNCTION inline_split_me (@SplitOn char(1),@String nvarchar(max)) 
RETURNS @results TABLE(Part NVARCHAR(MAX)) 
AS 
BEGIN 

    IF (CHARINDEX(@SplitOn,@String)-1<= 0) 
     INSERT INTO @results 
     SELECT @string AS Part 
    ELSE 
     WITH SplitSting AS 
      (
      SELECT 
       LEFT(@String,CHARINDEX(@SplitOn,@String)-1) AS Part 
        , CASE WHEN LEN(@String)-CHARINDEX(@SplitOn,@String) > 0 THEN RIGHT(@String,LEN(@String)-CHARINDEX(@SplitOn,@String)) ELSE NULL END AS Remainder 
       WHERE @String IS NOT NULL AND CHARINDEX(@SplitOn,@String)-1>0 
      UNION ALL 
      SELECT 
       LEFT(Remainder,CHARINDEX(@SplitOn,Remainder)-1) 
        ,RIGHT(Remainder,LEN(Remainder)-CHARINDEX(@SplitOn,Remainder)) 
       FROM SplitSting 
       WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)-1>0 
      UNION ALL 
      SELECT 
       Remainder,null 
       FROM SplitSting 
       WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)=0 
      ) 
      INSERT INTO @results 
      SELECT Part FROM SplitSting 

RETURN 
END 

GO 


CREATE TABLE #Product 
(
    prodID varchar(40) 
    , catID char(2) 
) 

CREATE TABLE #Category 
(
    catID varchar(4) 
    , description varchar(50) 
    , include bit --(actually a tinyint which should go to show what I deal with on a daily basis =P) 
    , atrID varchar(6) 
    , valID varchar(250) 
) 

CREATE TABLE #Attribute 
(
    prodID varchar(40) 
    , catID char(2) 
    , atrID varchar(10) 
    , valID varchar(10) 
) 

INSERT INTO #Product 
SELECT 'S101010', 'AA' 
UNION SELECT 'S202020', 'AA' 
UNION SELECT 'S303030', 'ED' 
UNION SELECT 'S404040', 'ED' 

INSERT INTO #Category 
SELECT 'AAA', 'Desktops', 0, 'A00432', 'K01819' 
UNION SELECT 'AAB', 'Servers', 1, 'A00432', 'K01819' 
UNION SELECT 'EDA', 'Laser Printers', 1, 'A00172', 'K00846,K00851' 
UNION SELECT 'EDB', 'Inkjet Printers', 1, 'A00172', 'K00845' 

INSERT INTO #Attribute 
SELECT 'S101010', 'AA', 'A00432', 'K01817' 
UNION SELECT 'S202020', 'AA', 'A00432', 'K01819' 
UNION SELECT 'S303030', 'ED', 'A00172', 'K00846' 
UNION SELECT 'S303030', 'ED', 'A00172', 'K00851' 

-- make sure it works with just one parameter 
SELECT * FROM dbo.inline_split_me(',', 'K00846') 

-- so you can see the split 
SELECT * FROM dbo.inline_split_me(',', 'K00846,K00851') 

-- so you can see the split in reference to the category 
SELECT c.*, Part 
FROM #Category c 
OUTER APPLY dbo.inline_split_me(',', c.valID) split 

SELECT p.*, a.*, c.* 
FROM #Product p 
INNER JOIN #Attribute a ON a.prodID = p.prodID AND a.catID = p.catID 
INNER JOIN #Category c ON c.atrID = a.atrID 
    AND (
      (c.include = 0 AND a.valID NOT IN (SELECT Part FROM dbo.inline_split_me(',', c.valID))) 
      OR (c.include = 1 AND a.valID IN (SELECT Part FROM dbo.inline_split_me(',', c.valID))) 
     ) 
ORDER BY a.ProdID, a.atrID--, c.catID 

DROP TABLE #Product 
DROP TABLE #Category 
DROP TABLE #Attribute 

DROP FUNCTION inline_split_me 
+0

미안하지만 나는 그다지 명확하지 않았다. 특정 제품에 대한 데이터를 얻으려고 할 때이 카테고리가 필요하지 않습니다. 제품 목록을 가져 와서 제품 카테고리를 가져 오는 데 사용할 수 있는지 알아보기 위해 사용하는 SQL을 포함 시켰습니다. – Sean

+0

귀하의 의견을 토대로 내 답변이 약간 변경되었습니다. 나는 우리가 'AAA'에서 'AA'로가는 방법에 관한 질문을 가지고있다. 문제를 해결할 수 있다면이 솔루션이 귀하에게 의미가 있습니까? –

+0

그래, 데이터는 꽤 나쁘지 만 내가 할 수있는 일은 아무것도 없다. CNet의 피드이다. 카테고리는 오래 전에 정의되었으며 이후 모든 사람들은 AAA 및 AAB에 대한 별도의 목록을 작성하는 데 익숙해졌습니다. 다른 시스템은 카테고리를 반복하여 적용된 마크 업을 얻고 가격을 다른 테이블에 저장하기 때문에 작동합니다. 그들이 속한 카테고리를 항상 압니다. 불행하게도 계정 관리자가 모든 클라이언트의 모든 제품에 대한 마크 업을 추가 할 수있는 가능성이 있기 때문에 동일한 방법으로는 옵션을 사용할 수 없다는 말을 들었습니다. – Sean

관련 문제