SELECT열을 사용하지 않고 열에 특정 데이터가있는 행 만 사용할 수있는 방법이 WHERE있습니까?
예를 들어 내가 이것을 가지고 있다면 :
SELECT * FROM Users
WHERE town = 'Townsville'
문에 WHERE절 을 구현하는 방법이 SELECT있습니까?
같은
SELECT *, town('Townsville') FROM Users
기괴한 질문이지만 동료들에게 내가 물었던 질문입니다.
SELECT열을 사용하지 않고 열에 특정 데이터가있는 행 만 사용할 수있는 방법이 WHERE있습니까?
예를 들어 내가 이것을 가지고 있다면 :
SELECT * FROM Users
WHERE town = 'Townsville'
문에 WHERE절 을 구현하는 방법이 SELECT있습니까?
같은
SELECT *, town('Townsville') FROM Users
기괴한 질문이지만 동료들에게 내가 물었던 질문입니다.
답변:
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
GROUP BY솔루션, 당신은 또한 목록으로 그룹의 PK를 추가 할 수 있습니다 (쿼리가 WHERE으로 동일한 행 수를 반환해야 100 %가 될 수 있습니다). 물론 PK가 있다고 가정;)
또 다른 방법.
SELECT U.*
FROM dbo.Users U
CROSS APPLY (SELECT Town INTERSECT SELECT 'Townsville' ) CA;
"즐거운 일" 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);
또 다른 버전 top과 order 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
여기 두 가지가 있습니다.
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'
내가 아직 보지 못한 바보 같은 논리적 방법 은 다음과 같습니다 ....
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
이것이 왜 이것이 처음 제안되지 않았는지 상상할 수 없습니다. :)