我有两个表,一个用户表和一个MyPhotos表。 UserTable包含UserID列和与用户信息相关的其他列。 MyPhotos表包含UserID和ImageFile列。
MyPhotos表可以为单个UserID提供多条记录。我需要一种方法来查找特定用户的照片总数,以及为每个UserID选择 ONE 随机的图像文件。
我当前使用的SQL语句每次都返回相同的图像而不是随机图像。这是:
SELECT MyPhotos.UserID,
UsrTbl.ScreenName, COUNT(*) AS TotalPhotos,
MAX(MyPhotos.ImagesFileName) AS Expr1
FROM MyPhotos
INNER JOIN UsrTbl ON MyPhotos.UserID = UsrTbl.AccountID
GROUP BY MyPhotos.UserID, UsrTbl.ScreenName
ORDER BY NEWID()
非常感谢任何帮助!
谢谢!
答案 0 :(得分:5)
我通常喜欢在tempdb中设置几个测试表,以便您可以使用该解决方案。我没有为设计添加任何完整性,因为你有真正的表格。
-- Just playing
use Tempdb;
Go
--
-- Table 1
--
-- Remove table
if OBJECT_ID('MyPhotos') > 0
drop table MyPhotos
go
-- Simple photo table
create table MyPhotos
(
UserID int,
ImagesFileName varchar(64)
);
-- Some data
insert into MyPhotos values
(1, 'c:\pics\fee.jpg'),
(1, 'c:\pics\fi.jpg'),
(1, 'c:\pics\foo.jpg'),
(1, 'c:\pics\fumb.jpg'),
(2, 'c:\pics\huff.jpg'),
(2, 'c:\pics\n.jpg'),
(2, 'c:\pics\puff.jpg');
-- Show the data
select * from MyPhotos
--
-- Table 2
--
-- Remove table
if OBJECT_ID('UsrTbl') > 0
drop table UsrTbl
go
-- Simple photo table
create table UsrTbl
(
AccountID int,
ScreenName varchar(64)
);
-- Some data
insert into UsrTbl values
(1, 'Jolly Green Giant'),
(2, 'Big Bad Wolf');
-- Show the data
select * from UsrTbl;
解决问题的一种方法是使用公用表表达式。
--
-- Grab a random pic by user id
--
;
WITH ctePhotos
as
(
SELECT
UserID, ImagesFileName,
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY UserID) as ImgNo
FROM
MyPhotos
),
cteRandomPick
AS
(
SELECT UserID, CEILING(RAND() * MAX(ImgNo)) AS ImgNo
FROM ctePhotos
GROUP BY UserId
)
SELECT
p.UserId,
u.ScreenName,
p.ImgNo,
p.ImagesFileName
FROM UsrTbl as u INNER JOIN ctePhotos as p ON u.AccountID = p.UserID
INNER JOIN cteRandomPick as r ON p.UserID = r.UserID and p.ImgNo = r.ImgNo;
ctePhones只是按用户ID枚举图片,图片编号。 cteRandomPick抓住了最大值 图像编号并将其乘以RAND()函数以获得随机图像。
最后但并非最不重要的是,身体连接两个CTE和用户表以获得结果。
如果你多次运行代码,你会得到不同的选择。
答案 1 :(得分:1)
1)如果我必须显示所有用户,那么我将使用以下查询:
SELECT u.AccountID, u.ScreenName, oa.RandomImagesFileName
FROM dbo.UsrTbl u
LEFT JOIN (
SELECT p.UserID, p.ImagesFileName AS RandomImagesFileName,
ROW_NUMBER() OVER(PARTITION BY p.UserID ORDER BY NEWID()) AS RowNum
FROM dbo.MyPhotos p
) oa ON u.AccountID = oa.UserID
WHERE oa.RowNum = 1
2)如果我必须显示单个用户或少数用户,那么我将使用以下查询:
SELECT u.AccountID, u.ScreenName, oa.RandomImagesFileName
FROM dbo.UsrTbl u
OUTER APPLY (
SELECT TOP(1) p.ImagesFileName AS RandomImagesFileName
FROM dbo.MyPhotos p -- Uncomment if execution plan includes a Scan; This WITH(INDEX=IX_MyPhotos_UserID_#_ImagesFileName) or WITH(FORCESEEK) table hints should "forces" DBMS to select an Index Seek instead of Scan
WHERE p.UserID = u.AccountID
ORDER BY NEWID()
) oa
WHERE u.AccountID IN (1, ...)
3)以下索引应该/可以帮助两个查询:
CREATE INDEX IX_MyPhotos_UserID_#_ImagesFileName
ON dbo.MyPhotos (UserID)
INCLUDE (ImagesFileName);
GO