Jin su un Select Grouped By

sabato 03 giugno 2006 - 14.27

aabruzzese Profilo | Junior Member

Ciao a tutti,

Sto cercando si e possibile di fare un JOIN con un Grouped By Select.

SELECT Top 1
forumThreads.psRelTopId
FROM forumThreads where forumThreads.psRelTopId > 0
GROUP BY forumThreads.psRelTopId

Questa query risulta in un psRelTopId e vorei rintraciare la colonna
psSubject di questa righa.

come si po aggiungere un JOIN in questo caso, sto cerdando di sapere
si e possibile di farlo con un solo select invece di usarne due.

Questo e compresso in un Stored Procedure.

Angelo Abruzzese

lbenaglia Profilo | Guru

>Sto cercando si e possibile di fare un JOIN con un Grouped By
>Select.

Ciao Angelo,

1) Quale DBMS stai utilizzando?
2) Posta la struttura delle tabelle (CREATE TABLE), alcune righe di prova (INSERT INTO) ed il result set che vuoi ottenere.

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member

Ciao Lorenzo,

MSSQL 2005 Express Edition.

Questa e la Sql Table:

USE [master]
GO
/****** Object: Table [dbo].[forumThreads] Script Date: 06/03/2006 06:35:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[forumThreads](
[psId] [int] IDENTITY(1,1) NOT NULL,
[psRelTopId] [int] NULL,
[psName] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[psEmail] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[psSubject] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[psPost] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[psDate] [datetime] NULL,
[psRelBcId] [int] NULL,
[psLastUpdate] [datetime] NULL,
[psIP] [varchar](20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[psViews] [int] NULL,
[psSticky] [char](1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL CONSTRAINT [DF_forumThreads_psSticky] DEFAULT ('n')
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
SET ANSI_PADDING OFF


Questo e un essempio dei dati:

SELECT psId, psRelTopId, psSubject
FROM forumThreads

psId psRelTopId psSubject
----------- ----------- ------------------------------------------------------------------------------
5 0 Where do you play Online ?
11 0 Poker Night at Gina's during the Month of April
3 0 Forum rules
12 0 Black Hawk - Isle of Capri
13 0 UltimateBet.net
16 0 Test in Poker Beginners
17 16 RE: Test in Poker Beginners
18 16 RE: Test in Poker Beginners

Quello che sto cercando e di fare un return dal Stored Procedure con il valore "Test in Poker Beginners "

Questa e una Table da un Forum quando si vedi psRelTopId = 0 vuol dire che il Thread non a risposte, quindi il where forumthreads.psRelTopId > 0 entro il Select.




Angelo Abruzzese

lbenaglia Profilo | Guru

>Quello che sto cercando e di fare un return dal Stored Procedure
>con il valore "Test in Poker Beginners "
>
>Questa e una Table da un Forum quando si vedi psRelTopId = 0
>vuol dire che il Thread non a risposte, quindi il where forumthreads.psRelTopId > 0
>entro il Select.

Argh, non riesci ad essere un po' più chiaro (anche per quanto riguarda l'italiano)?!
Nel tuo esempio solo il thread con psId = 16 ha risposte. Nel caso esistano altri threads con almeno una risposta cosa vuoi ottenere in output?

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member

Lorenzo,

Son pui di venti anni che non scrivo pui in Italiano, spero che questo lo poi capire.

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go


-- =============================================
-- Author: Angelo Abruzzese
-- Create date:
-- Description:
-- =============================================
ALTER PROCEDURE [dbo].[getForumStats]
-- Add the parameters for the stored procedure here
@UsersWithThreads int OUTPUT,
@NumberofThreads int OUTPUT,
@NumberofPosts int OUTPUT,
@NewThreads int OUTPUT,
@NewPosts int OUTPUT,
@NewUsers int OUTPUT,
@MostViews varchar OUTPUT,
@EndTime datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @SQLUsersWithThreads int;
DECLARE @SQLNumberofThreads int;
DECLARE @SQLNumberofPosts int;
DECLARE @SQLNewThreads int;
DECLARE @SQLNewPosts int;
DECLARE @SQLNewUsers int;
DECLARE @SQLMostViews varchar;

SET @SQLUsersWithThreads = (SELECT Count(Distinct PSNAME) FROM forumThreads);
SET @SQLNumberofThreads = (SELECT Count(*) FROM forumThreads where PsRelTopId = 0);
SET @SQLNumberofPosts = (SELECT Count(*) FROM forumThreads);
SET @SQLNewThreads = (SELECT Count(*) FROM forumThreads where psDate >= @EndTime and PsRelTopId = 0);
SET @SQLNewPosts = (SELECT Count(*) FROM forumThreads where psDate >= @EndTime);
SET @SQLNewUsers = (SELECT Count(*) FROM aspnet_Membership where CreateDate >= @EndTime);
SET @SQLMostViews = (SELECT TOP 1 psSubject FROM forumThreads order by psViews desc);

SET @UsersWithThreads=@SQLUsersWithThreads;
SET @NumberofThreads=@SQLNumberofThreads;
SET @NumberofPosts=@SQLNumberofPosts;
SET @NewThreads=@SQLNewThreads;
SET @NewPosts=@SQLNewPosts;
SET @NewUsers=@SQLNewUsers;
SET @MostViews=@SQLMostViews;

End

Questa e la Stored Procedure.

Diciamo questo.

La Stored Procedure mi risponda con il Thread con pui risposte dei altri.

PsRelTopId = 0 vuol dire che la Righe non e attached(associated) ad un altra.

psId = 16 -----> Post #16 in the Forums
psRelTopId = 16 ----> Una Risposta a Post #16

Nel mio caso soltanto psId = 16 a delle risposte.


Angelo Abruzzese

lbenaglia Profilo | Guru

>Lorenzo,
>
>Son pui di venti anni che non scrivo pui in Italiano, spero che
>questo lo poi capire.

OK, se preferisci puoi scrivere in inglese

>La Stored Procedure mi risponda con il Thread con pui risposte
>dei altri.

E se 2 o più threads hanno lo stesso numero di risposte cosa vuoi ottenere in output?

> Nel mio caso soltanto psId = 16 a delle risposte.

Ho capito, ma difficilmente in un forum avrai solo un thread con alcune risposte

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member


Yes of course it would be rare to have only a few threads with replies, the main thing is that this a still in development so I don't expect that.

The Top 1 as a returned row even if there are two rows that qualify.

So if psId = 16 has 2 replies and psId = 24 has 2 replies , the stored procedure should return the subject associated to psId = 16.


Angelo Abruzzese

lbenaglia Profilo | Guru

>So if psId = 16 has 2 replies and psId = 24 has 2 replies , the
>stored procedure should return the subject associated to psId
>= 16.

Angelo, have a look to this code:

USE tempdb; GO CREATE TABLE dbo.forumThreads( psId int NOT NULL, psRelTopId int NULL, psSubject varchar(255) NULL ); GO INSERT dbo.forumThreads VALUES(5, 0, 'Where do you play Online?'); INSERT dbo.forumThreads VALUES(11, 0, 'Poker Night at Gina''s during the Month of April'); INSERT dbo.forumThreads VALUES(3, 0, 'Forum rules'); INSERT dbo.forumThreads VALUES(12, 0,'Black Hawk - Isle of Capri'); INSERT dbo.forumThreads VALUES(13, 0, 'UltimateBet.net'); INSERT dbo.forumThreads VALUES(14, 13, 'RE: UltimateBet.net'); INSERT dbo.forumThreads VALUES(15, 0, 'T-SQL Programming'); INSERT dbo.forumThreads VALUES(16, 0, 'Test in Poker Beginners'); INSERT dbo.forumThreads VALUES(17, 16, 'RE: Test in Poker Beginners'); INSERT dbo.forumThreads VALUES(18, 16, 'RE: Test in Poker Beginners'); INSERT dbo.forumThreads VALUES(19, 15, 'RE: T-SQL Programming'); INSERT dbo.forumThreads VALUES(20, 15, 'RE: T-SQL Programming'); GO /* This query gets the number of answers for every thread */ SELECT psRelTopId, COUNT(*) AS Answers FROM dbo.forumThreads WHERE psRelTopId > 0 GROUP BY psRelTopId; GO /* Output: psRelTopId Answers ----------- ----------- 13 1 15 2 16 2 (3 row(s) affected) */ /* I have to get the first thread with most answers (psRelTopId = 15). ** I can achieve this result ordering the result set in descending order ** by the number of answers and in ascending order by psRelTopId and ** getting only the first row */ SELECT TOP 1 psRelTopId, COUNT(*) AS Answers FROM forumThreads WHERE psRelTopId > 0 GROUP BY psRelTopId ORDER BY Answers DESC, psRelTopId; GO /* Output: psRelTopId Answers ----------- ----------- 15 2 (1 row(s) affected) */ /* OK, and now I need a simple INNER JOIN with the base table ** to get the Subject */ SELECT T.psSubject FROM dbo.forumThreads AS T JOIN ( SELECT TOP 1 psRelTopId, COUNT(*) AS Answers FROM forumThreads WHERE psRelTopId > 0 GROUP BY psRelTopId ORDER BY Answers DESC, psRelTopId ) AS Q ON T.psId = Q.psRelTopId; GO /* Output: psSubject ------------------- T-SQL Programming (1 row(s) affected) */ DROP TABLE dbo.forumThreads;

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member


Ciao Lorenzo,

That may well work but it seems like a bit of overkill, how would that perform under load?

I made a temporary solution for now:

SET @SQLMostViewedThread =
(SELECT Top 1
forumThreads.psRelTopId
FROM forumThreads where forumThreads.psRelTopId > 0
GROUP BY forumThreads.psRelTopId)

SET @SQLMostViews =
(SELECT
forumThreads.psSubject
FROM forumThreads where forumThreads.psId = @SQLMostViewedThread)


This is quick and dirty and sometimes Good Enough is just that Good Enough.

Grazie del auito.


Angelo Abruzzese

lbenaglia Profilo | Guru

>That may well work but it seems like a bit of overkill, how would
>that perform under load?

It will perform very well if your index policy will be right.

> I made a temporary solution for now:
>
> SET @SQLMostViewedThread =
> (SELECT Top 1
> forumThreads.psRelTopId
> FROM forumThreads where forumThreads.psRelTopId > 0
> GROUP BY forumThreads.psRelTopId)
>
> SET @SQLMostViews =
> (SELECT
> forumThreads.psSubject
> FROM forumThreads where forumThreads.psId = @SQLMostViewedThread)

This solution is not correct because your first query does not return *THE FIRST* thread with the maximum number of answers!!
If you execute your query with my last data, you get psRelTopId = 13 that is a mistake!

>This is quick and dirty and sometimes Good Enough is just that
>Good Enough.

No, it's just dirty

> Grazie del auito.

You're welcome.

Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member


Ciao Lorenzo,

My appologies on that previous reply, it never pays to read code while your wife is hounding you to get ready to go shopping.

I tried your code and it works fine, the reason I thought it was overkill is that at a quick glance it almost looked like you wanted me to create a temp table to hold data and then wipe it out.

The query you posted with the join works perfectly and does what I was looking for.

Once again thanks.

Forza Azzuri !
Questa volta non perderemo sui Penalty Kicks e niente di quelli Arbitri deliquenti !

Io sto qui nel Colorado.

Angelo Abruzzese

lbenaglia Profilo | Guru

>My appologies on that previous reply, it never pays to read code
>while your wife is hounding you to get ready to go shopping.
>

Ha, ha, ha...

>I tried your code and it works fine, the reason I thought it
>was overkill is that at a quick glance it almost looked like
>you wanted me to create a temp table to hold data and then wipe
>it out.
No, I use the tempdb only to not "dirty" your work db. You don't need any temp table

>The query you posted with the join works perfectly and does what
>I was looking for.

I'm happy to hear it

>Once again thanks.

You're welcome.

>
>Forza Azzuri !
>Questa volta non perderemo sui Penalty Kicks e niente di quelli
>Arbitri deliquenti !

Speriamo di non fare una figuraccia

>Io sto qui nel Colorado.

WOW, che meraviglia!
Con quelle montagne chissà che belle sciate farai...

Ciao!

--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org

aabruzzese Profilo | Junior Member


Ciao Lorenzo,

guisto in caso si voresti vedere a qualle fina era tutto quello SQL.

http://67.164.255.166:8029/forums.aspx

Angelo Abruzzese
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5