WHERE 절에 대한 대안 [닫힘]


16

SELECT열을 사용하지 않고 열에 특정 데이터가있는 행 만 사용할 수있는 방법이 WHERE있습니까?

예를 들어 내가 이것을 가지고 있다면 :

SELECT * FROM Users
WHERE town = 'Townsville'

문에 WHERE절 을 구현하는 방법이 SELECT있습니까?

같은

SELECT *, town('Townsville') FROM Users

기괴한 질문이지만 동료들에게 내가 물었던 질문입니다.


4
그들이 왜 이런 질문을하는지 물어보십시오. 상황이 중요합니다.
Aaron Bertrand

@AaronBertrand, MikaelEriksson-기본적으로 직장에서의 SQL에 대한 약간의 설문지입니다. "Where 절을 사용하지 않고 Townsville에서 온 users 테이블에서 모든 사용자를 선택하십시오"라는 질문이 나왔습니다. 가능했다! 어쩌면 내가 잘못된 길로 다가 가고 있을까 ..?
Josh Stevenson

또한이 설문지는 회사에 대한 나의 고용 상태와 관련이 없다고 진술합니다! 재미의 조금의
조쉬 스티븐슨에게

답변:


17

이것이 당신이 찾고있는 미친 종류인지 확실하지 않습니다 ....

면책 조항 : 나는 왜 당신이 이것을 사용하고 싶어하는지 전혀 모른다.

SELECT * 
FROM Users AS u
INNER JOIN (SELECT 'Townsville' town) towns 
  ON towns.town = u.Town;

17

데이터

DECLARE @Example AS table
(
    UserName varchar(30) NULL,
    Town varchar(30) NULL
);

INSERT @Example
    (UserName, Town)
VALUES
    ('Aaron', 'Not Townsville'),
    ('Bob', 'Not Townsville'),
    ('Charles', 'Townsville'),
    ('Charles', 'Townsville'),
    ('Charles', 'Townsville'),
    ('Charles', 'Townsville'),
    ('Dan', 'Townsville'),
    ('Eric', 'Not Townsville');

대체 솔루션

SELECT E.UserName, E.Town
FROM @Example AS E
GROUP BY E.Town, E.UserName
HAVING E.Town = 'Townsville'

-- OR

SELECT E.UserName, 'Townsville' AS Town
FROM @Example AS E
GROUP BY E.UserName
HAVING 1 = MAX(CASE WHEN E.Town = 'Townsville' THEN 1 ELSE 0 END);

-- OR

SELECT E.UserName, E.Town
FROM @Example AS E
INTERSECT
SELECT E.UserName, 'Townsville' AS Town
FROM @Example AS E

중복 유지

-- :)
SELECT E.UserName, E.Town
FROM @Example AS E
CROSS APPLY (VALUES(NEWID())) AS CA (n)
GROUP BY E.Town, E.UserName, CA.n
HAVING E.Town = 'Townsville'

-- Simulating INTERSECT ALL
SELECT
    R.UserName,
    R.Town
FROM 
(
    SELECT 
        E.UserName, 
        E.Town, 
        rn =
            ROW_NUMBER() OVER (
                PARTITION BY E.UserName, E.Town 
                ORDER BY E.UserName, E.Town)
    FROM @Example AS E
    INTERSECT
    SELECT 
        E.UserName, 
        'Townsville', 
        rn = 
        ROW_NUMBER() OVER (
            PARTITION BY E.UserName 
            ORDER BY E.UserName)
    FROM @Example AS E
) AS R;

산출:

╔══════════╦════════════╗
 UserName     Town    
╠══════════╬════════════╣
 Charles   Townsville 
 Dan       Townsville 
╚══════════╩════════════╝

마지막 예 :

╔══════════╦════════════╗
 UserName     Town    
╠══════════╬════════════╣
 Charles   Townsville 
 Charles   Townsville 
 Charles   Townsville 
 Charles   Townsville 
 Dan       Townsville 
╚══════════╩════════════╝

여기에서보십시오 : Stack Exchange Data Explorer


아주 좋아요! 'Username'과 같은 고유 한 데이터 만 포함하는 열이없는 시나리오에서 이것을 사용할 수 없다고 생각합니다. 예를 들어 성, 성, 도시 만 있다면
Josh Stevenson

3
@JoshStevenson Correct, 마지막 예제로 복제본을 보존하는 적절한 방법을 추가 한 다음 합리적인 방법을 추가했습니다.
폴 화이트 복원 모니카

1
를 들어 GROUP BY솔루션, 당신은 또한 목록으로 그룹의 PK를 추가 할 수 있습니다 (쿼리가 WHERE으로 동일한 행 수를 반환해야 100 %가 될 수 있습니다). 물론 PK가 있다고 가정;)
ypercubeᵀᴹ


14

"즐거운 일" order by과 함께 사용할 수 있습니다top(1) with ties

select top(1) with ties *
from dbo.Users
order by case when town = 'Townsville' then 1 else 2 end;

Townsville경우 case가 1if를 반환하므로 모든 행이 먼저 정렬 됩니다 town = 'Townsville'. 다른 모든 행은 2사례에 의해 반환됩니다.

그만큼 with ties 절은 쿼리가 반환 된 행의 마지막 위치에 대해 "tie"인 모든 행을 반환하도록합니다. 사용 top(1)과 조합하면 with ties다음 절에서 순서대로 사용되는 식의 첫 번째 행과 동일한 값을 갖는 모든 행을 반환한다.

Martin Smith가 의견에서 지적했듯이 반환됩니다. 테이블에 존재하지 않는 도시를 요청하면 모든 행 합니다.

데이터베이스의 XML을 두려워하지 않으면 nodes () 함수에서 술어를 사용할 수 있습니다.

Paul White에서 설정을 차용합니다.

select T.X.value('(UserName/text())[1]', 'varchar(30)') as UserName,
       T.X.value('(Town/text())[1]', 'varchar(30)') as Town
from (
     select *
     from @Example
     for xml path('row'), type 
     ) as C(X)
  cross apply C.X.nodes('/row[Town = "Townsville"]') as T(X);

또 다른 버전 toporder by실제로 작품은 존재하지 않는 도시를 검색 할 때.

select top(
          select sum(case when town = 'Townsville' then 1 end)
          from @Example
          ) *
from @Example
order by case when town = 'Townsville' then 1 else 2 end

7

여기 두 가지가 있습니다.

SELECT * FROM Users
WHERE town = 'Townsville'

다시 돌아 오는 행 수를 town =Townsville

SELECT *, town('Townsville') FROM Users

리터럴 Townsville을라는 함수 에 전달합니다 town. 쿼리에서 반환되는 행을 제한하지 않으며 실제로 함수가 단일 값 이외의 값을 반환하면 오류가 발생합니다.

쿼리에서 반환되는 행 수를 제한하는 다른 방법이 있습니다. 예를 들어 HAVING 절. 그러나 몇 가지 다른 요구 사항이 있습니다.

SELECT town FROM Users
GROUP BY town
HAVING town = 'Townsville'

또는 두 번째 테이블이 없으면 조금 이상하지만 INNER JOIN입니다.

SELECT * FROM Users
INNER JOIN (SELECT 1 col1) UselessTable
    ON Users.town = 'Townsville'

5

다음은 CTE (Common Table Expression)를 사용하는 예입니다.

with Town as 
(
    select 'Townsville' as Town
)
select *
  from Users u
  join Town  t on u.Town = t.Town

5

글쎄, 당신은 이것을 할 수 있습니다 :

    SELECT A.* 
    FROM Users A
         INNER JOIN Users B ON A.Id = B.Id AND B.town = 'Townsville'

엄밀히 말하면 WHERE 절을 사용하지 않습니다.


5

내가 아직 보지 못한 바보 같은 논리적 방법 은 다음과 같습니다 ....

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;  -- Our important work should be all the database cares about
GO
BEGIN TRANSACTION

DECLARE @MyTableVar table(<all columns in order from the user table>, oldtown VARCHAR(50));

UPDATE users
SET town = N'Townsville'
OUTPUT 
     inserted.*  -- We don't want to have to type out the columns because that would be too much work
    deleted.town
INTO @MyTableVar;

--Display the result set of the table variable to prevent undesirables from sullying our output by inserting incorrect data even though we should have exclusive access.
SELECT * -- Select everything we want except for the 'oldtown' column because that data was probably wrong anyway
FROM @MyTableVar;

UPDATE u -- We don't want to be bad stewards of our data
SET
    town = oldtown
FROM users u
    INNER JOIN @MyTableVar mtv ON mtv.town = u.town, <Match up all the columns to REALLY ensure we are matching the proper row>

COMMIT TRANSACTION -- Make sure we save our work

이것이 왜 이것이 처음 제안되지 않았는지 상상할 수 없습니다. :)


-2
SELECT *, 
    case when town='Townsville' then 'Townsville' 
         else null 
    end as Town
FROM Users

Townsville 이외의 모든 도시는 null입니다. 문제 해결됨.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.