I'm banging my head here. I feel pretty stupid because I'm sure I've done something like this before, but can't for the life of me remember how. One of those days I guess >.<
Say I have the following data: ---> and a query which returns this: ---> But I want this:
ID FirstID ID FirstID ID FirstID
-- ------- -- ------- -- -------
1 1 1 1 7 1
2 1 3 3 3 3
3 3 4 4 6 4
4 4 5 5 5 5
5 5
6 4
7 1
Notice that my query returns the records where ID = FirstID, but I want it to return the Max(ID) for each subset of unique FirstID. Sounds simple enough right? That's what I thought, but I keep getting back just record #7. Here's my query (the one that returns the second block of figures above) with some test code to make your life easier. I need this to give me the results in the far right block. It should be noted that this is a self-joining table where FirstID is a foreign key to ID. Thanks :)
declare #MyTable table (ID int, FirstID int)
insert into #MyTable values (1,1),(2,1),(3,3),(4,4),(5,5),(6,4),(7,1)
select ID, FirstID
from #MyTable
where ID = FirstID
Does this work
declare #MyTable table (ID int, FirstID int)
insert into #MyTable values (1,1),(2,1),(3,3),(4,4),(5,5),(6,4),(7,1)
Select FirstID, Max (Id) ID
From #MyTable
Group BY FirstID
Results in
FirstID ID
----------- -----------
1 7
3 3
4 6
5 5
With SQL2005 and later SQL2008 versions the Aggregate functions in SQL Server have been improved
You can use PARTITION BY clause for example with MAX,MIN,SUM,COUNT functions
Please try the following example
select
Distinct FirstID, Max(ID) OVER (PARTITION BY FirstID) MaxID
from #MyTable
You can find an example at http://www.kodyaz.com/t-sql/sql-count-function-with-partition-by-clause.aspx
Upon your comment, I modified the same query just to provide the exact output in order of rows and columns as follows
select Distinct
Max(ID) OVER (PARTITION BY FirstID) ID,
FirstID
from #MyTable
order by FirstID
Related
I'm trying to select randomly few rows for each Id stored in one table where these Ids have multiple rows on this table. It's difficult to explain with words, so let me show you with an example :
Example from the table :
Id Review
1 Text11
1 Text12
1 Text13
2 Text21
3 Text31
3 Text32
4 Text41
5 Text51
6 Text61
6 Text62
6 Text63
Result expected :
Id Review
1 Text11
1 Text13
2 Text21
3 Text32
4 Text41
5 Text51
6 Text62
In fact, the table contains thousands of rows. Some Ids contain only one Review but others can contain hundreds of reviews. I would like to select 10% of these, and select at least once, all rows wich have 1-9 reviews (I saw the SELECT TOP 10 percent FROM table ORDER BY NEWID() includes the row even if it's alone)
I read some Stack topics, I think I have to use a subquery but I don't find the correct solution.
Thanks by advance.
Regards.
Try this:
DECLARE #t table(Id int, Review char(6))
INSERT #t values
(1,'Text11'),
(1,'Text12'),
(1,'Text13'),
(2,'Text21'),
(3,'Text31'),
(3,'Text32'),
(4,'Text41'),
(5,'Text51'),
(6,'Text61'),
(6,'Text62'),
(6,'Text63')
;WITH CTE AS
(
SELECT
id, Review,
row_number() over (partition by id order by newid()) rn,
count(*) over (partition by id) cnt
FROM #t
)
SELECT id, Review
FROM CTE
WHERE rn <= (cnt / 10) + 1
Result(random):
id Review
1 Text12
2 Text21
3 Text31
4 Text41
5 Text51
6 Text63
I have a SQL question. Below is my data and query
select ID from table
ID
4
4
5
3
5
3
3
What query should I add to my select list so that it gives me the occurrence of a value for each specfic row(I do not want the total count, I want something like a rank of occurrence).
4 1--this is the first time we got a 4 in the list, so 1
4 2--this is the second time we got a 4 in the list, so 2
5 1--this is the first time we got a 5 in the list, so 1
3 1--this is the first time we got a 3 in the list, so 1
5 2--this is the second time we got a 5 in the list, so 2
3 2--this is the second time we got a 3 in the list, so 2
3 3--this is the third time we got a 3 in the list, so 3
You want ROW_NUMBER():
SELECT
[Id],
ROW_NUMBER() OVER (PARTITION BY [Id] ORDER BY [Id])
FROM ...
You'll probably need to change the Order By clause to get the right output.
To generate a numbering from an order of rows, use row_number() or rank(). The problem is, row_number() does not guarantee the original order will be preserved. You could try this:
select
[id],
row_number() over (partition by id, order by (select 1)) as [rank]
from #t
However, you will find the results are not in the original order and somewhat confusing:
id rank
3 1
3 2
3 3
4 1
4 2
5 1
5 2
To preserve the original row order, you could build a temporary table or table variable with an identity column. Select a row_number() partitioned by id from there:
declare #t table ([tkey] int identity(1,1) primary key clustered, [id] int)
insert into #t (id) values (4), (4), (5), (3), (5), (3), (3)
select
[id],
row_number() over (partition by [Id] order by [tkey]) as [rank]
from #t
order by [tkey]
Note that the final order by [tkey] really is necessary. The query has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
Here is a Common Table Expression (CTE) approach. The CTE adds a row_number() to maintain the rows in the original order. (This is the equivalent of the identity column in the previous example.) The actual ranking comes with the second row_number() when it does a partition by id. This causes the 1st 4 gets 1, the 2nd 4 gets 2, etc.
The second row_number() must be ordered by the original order to rank correctly, but this is still not enough to preserve the order in the output. A final order by ensures the ending order is the same.
declare #t table (id int)
insert into #t (id) values (4), (4), (5), (3), (5), (3), (3)
;with [tRows] (rownum, id) as
(
select
row_number() over (order by (select 1)) as [rownum],
[id]
from #t
)
select
[id],
row_number() over (partition by id order by [rownum]) as [rank]
from [tRows]
order by [rownum]
This query also has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
In this example, you could use rank() instead of the second row_number(). The difference between the functions is explained well in this question. rank() would not work the same if, somehow, there were duplicate row numbers generated by the first row_number(), but that cannot happen.
My Apologies for the appalling Title, I was trying to be descriptive but not sure I got to the point. Hopefully the below will explain it
I begin with a table that has the following information
Party Id Party Name Party Code Parent Id
1 Acme 1 ACME1 1
2 Acme 2 ACME2 1
3 Acme 3 ACME3 3
4 Acme 4 ACME4 4
5 Acme 5 ACME5 4
6 Acme 6 ACME6 6
As you can see this isn't perfect for a recursive CTE because rather than having a NULL where there isn't a parent record it is instead parented to itself (see rows 1,3 and 6). Some however are parented normally.
I have therefore tried to amend this table in a CTE then refer to the output of that CTE as part of my recursive query... This doesn't appear to be running very well (no errors yet) so I wonder if I have managed to create an infinite loop or some other error that just slows the query to a crawl rather than killing it
My Code is below... please pick it apart!
--This is my attempt to 'clean' the data and set records parented to themselves as the 'anchor'
--record
WITH Parties
AS
(Select CASE
WHEN Cur_Parent_Id = Party_Id THEN NULL
ELSE Cur_Parent_Id
END AS Act_Parent_Id
, Party_Id
, CUR_PARTY_CODE
, CUR_PARTY_NAME
FROM EDW..TBDIMD_PARTIES
WHERE CUR_FLG = 1),
--In this CTE I referred to my 'clean' records from above and then traverse through them
--looking at the actual parent record identified
linkedParties
AS
(
Select Act_Parent_Id, Party_Id, CUR_PARTY_CODE, CUR_PARTY_NAME, 0 AS LEVEL
FROM Parties
WHERE Act_Parent_Id IS NULL
UNION ALL
Select p.Act_Parent_Id, p.Party_Id, p.CUR_PARTY_CODE, p.CUR_PARTY_NAME, Level + 1
FROM Parties p
inner join
linkedParties t on p.Act_Parent_Id = t.Party_Id
)
Select *
FROM linkedParties
Order By Level
From the data I supplied earlier the results I would expect are;
Party Id Party Name Party Code Parent Id Level
1 Acme 1 ACME1 1 0
3 Acme 3 ACME3 3 0
4 Acme 4 ACME4 4 0
6 Acme 6 ACME6 6 0
2 Acme 2 ACME2 1 1
5 Acme 5 ACME5 4 1
If everything seems to be OK then I'll assume its just a processing issue and start investigating that but I am not entirely comfortable with CTE's so wish to make sure the error is not mine before looking elsewhere.
Many Thanks
I think that you made it more complicated than it needs to be :).
drop table #temp
GO
select
*
into #temp
from (
select '1','Acme 1','ACME1','1' union all
select '2','Acme 2','ACME2','1' union all
select '3','Acme 3','ACME3','3' union all
select '4','Acme 4','ACME4','4' union all
select '5','Acme 5','ACME5','4' union all
select '6','Acme 6','ACME6','6'
) x ([Party Id],[Party Name],[Party Code],[Parent Id])
GO
;with cte as (
select
*,
[Level] = 0
from #temp
where 1=1
and [Party Id]=[Parent Id] --assuming these are root records
union all
select
t.*,
[Level] = c.[Level]+1
from #temp t
join cte c
on t.[Parent Id]=c.[Party Id]
where 1=1
and t.[Party Id]<>t.[Parent Id] --prevent matching root records with themselves creating infinite recursion
)
select
*
from cte
(* should ofcourse be replaced with actual column names)
I am struggling with the following:
Counter --- Period ---
1 2012-02-09
1 2012-02-09
1 2012-02-08
2 2012-02-07
2 2012-02-07
2 2012-02-07
3 2012-02-06
3 2012-02-06
I don't know what function to use or how to add a counter column that will divide the period rows in the table by 3 and add a counts. It will divide until it can and assign the leftover rows as the next counter (as shown above). In the example above #n is 3 so it counts each period assigns 1 until 3 are complete and counters.
I have looked at NTILE that does not work as it just divides it into n groups.
Help will be greatly appreciated.
It's possible you need to clarify your question; if I use NTILE() I get the result you're looking for (if you include an ID):
declare #tableA table(id int identity, col1 date)
insert into #tableA values ('2012-02-09')
insert into #tableA values ('2012-02-09')
insert into #tableA values ('2012-02-08')
insert into #tableA values ('2012-02-07')
insert into #tableA values ('2012-02-07')
insert into #tableA values ('2012-02-07')
insert into #tableA values ('2012-02-06')
insert into #tableA values ('2012-02-06')
select ntile(3) over (order by id) counter, col1 Period from #tableA
Results:
counter Period
-------------------- ----------
1 2012-02-09
1 2012-02-09
1 2012-02-08
2 2012-02-07
2 2012-02-07
2 2012-02-07
3 2012-02-06
3 2012-02-06
Are you looking for something like:
declare #n as int = 3
SELECT
((ROW_NUMBER() over (order by period desc) - 1) / #n) + 1 as counter,
[period]
FROM [a].[dbo].[a]
I have a SQL insert statement like the following:
insert into mytable(ID,Keyindex,KeyValue)
select Id,1,GenreID
from mytable2
Which should populate my table with data like:
id GenreID ColumnB
0006342c-47bc-436a-a23a-3b40360d9a30 16 1
0006342c-47bc-436a-a23a-3b40360d9a30 19 1
00109775-f0f8-463e-8134-f842aac8b5df 12 1
001211e3-9bf8-45ad-8297-7a0a94aaf06e 13 1
0025218a-9624-4f5e-86cc-f1cfe862cd2a 16 1
0025218a-9624-4f5e-86cc-f1cfe862cd2a 11 1
0025218a-9624-4f5e-86cc-f1cfe862cd2a 15 1
The problem is ID,GenreId and ColumnB are primary keys and I am currently inserting a constand value "1" which results in a primary key violation.
How do I insert into the table so that ColumnB gets populated with a value incrementaly if the IDs are the same.
For example:
id GenreID ColumnB
0006342c-47bc-436a-a23a-3b40360d9a30 16 1
0006342c-47bc-436a-a23a-3b40360d9a30 19 2
00109775-f0f8-463e-8134-f842aac8b5df 12 1
001211e3-9bf8-45ad-8297-7a0a94aaf06e 13 1
0025218a-9624-4f5e-86cc-f1cfe862cd2a 16 1
0025218a-9624-4f5e-86cc-f1cfe862cd2a 16 2
0025218a-9624-4f5e-86cc-f1cfe862cd2a 16 3
Your question is a little confusing. In the "for example" section it looks like the genreID for 0025218a-9624-4f5e-86cc-f1cfe862cd2a should be 16,17,19 instead of 16,16,16.
Assuming I understand you correct, though, you can use ROW_NUMBER() OVER partitioned by the id. Something like the following should work :
insert into mytable(ID,Keyindex,KeyValue)
select id, GenreID , ROW_NUMBER() OVER (Partition by id order by id) as ColumnB
from mytable2
order by id,
genereid
Note: you didn't specify version, but this will work in sql 2005+
A dirty hack would be to use id - someNumber or id + someNumber instead of just 1.
What can be accepted if this is a "fire and forget" one time operation.
If you have to check the uniqueness, then a trigger can be the solution.
You could try the ON DUPLICATE option:
insert into mytable(ID,Keyindex,KeyValue)
select Id,1,GenreID
from mytable2
ON DUPLICATE KEY UPDATE Keyindex = Keyindex+1;