GROUP BY adjacent records
If I understand you correctly: What you want is a result that is dependent on the value in the next record. If the value of value
is different, it starts a new subgroup. We can find the first row from the next group for every row. For that we can use an auto join, based on unequality. Of course the last row(s) of your data will go missing as they have no next row with a different value
. (Maybe you could fix this by adding a fake row with future date and nonexisting value
by using UNION.)
Then from this list of data where we know the starting date of the next group for each member, we can use that Nextdate
for grouping so we can find the first and last date within that group as well:
SELECT Min(Somedate) AS timest_first, Max(Somedate) AS timest_last, value FROM
(SELECT t2.Value, t2.timest AS Somedate, Min(t1.timest) AS Nextdate, t1.value as n
FROM entity_log t1 JOIN entity_log t2
ON t1.timest > t2.timest
WHERE t1.value <> t2.value
GROUP BY t2.timest) s1
GROUP BY value, Nextdate
ORDER BY 2 desc
How to get aggregate data from a dynamic number of related rows in adjacent table
I think this does what you want.
The key idea is to assign a "streak group" to each winning streak, so you can aggregate them. You can do this by observing:
- A match in a winning streak is obviously a "win".
- A winning streak can be identified by counting the number of losses before it -- this is constant for the streak.
Postgres introduced the filter
clause in 9.4, which makes the syntax a little easier:
select player_id, count(*) as streak_length,
avg(opponent_rank) as avg_opponent_rank
from (select m.*,
count(*) filter (where result = 'l') over (partition by player_id order by date) as streak_grp
from matches_m m
) m
where result = 'w'
group by player_id, streak_grp;
Merge adjacent rows in SQL?
This article provides quite a few possible solutions to your question
http://www.sqlmag.com/blog/puzzled-by-t-sql-blog-15/tsql/solutions-to-packing-date-and-time-intervals-puzzle-136851
This one seems like the most straight forward:
WITH StartTimes AS
(
SELECT DISTINCT username, starttime
FROM dbo.Sessions AS S1
WHERE NOT EXISTS
(SELECT * FROM dbo.Sessions AS S2
WHERE S2.username = S1.username
AND S2.starttime < S1.starttime
AND S2.endtime >= S1.starttime)
),
EndTimes AS
(
SELECT DISTINCT username, endtime
FROM dbo.Sessions AS S1
WHERE NOT EXISTS
(SELECT * FROM dbo.Sessions AS S2
WHERE S2.username = S1.username
AND S2.endtime > S1.endtime
AND S2.starttime <= S1.endtime)
)
SELECT username, starttime,
(SELECT MIN(endtime) FROM EndTimes AS E
WHERE E.username = S.username
AND endtime >= starttime) AS endtime
FROM StartTimes AS S;
Group consecutive rows of same value using time spans
The query determines each rows EndTime
by using NOT EXISTS
to make sure no other class or course of a different type is scheduled between a course range's StartTime
and EndTime
and then uses MIN
and GROUP BY
to find the StartTime
.
The NOT EXISTS
part ensures that there aren't "breaks" between the StartTime
and EndTime
ranges by searching for any rows that have an EndTime
between StartTime
and EndTime
but belong to a different CourseName
or CourseRoom
.
SELECT
t0.ClassRoom,
t0.CourseName,
MIN(t0.StartTime),
t0.EndTime
FROM (
SELECT
t1.ClassRoom,
t1.CourseName,
t1.StartTime,
(
SELECT MAX(t2.EndTime)
FROM tableA t2
WHERE t2.CourseName = t1.CourseName
AND t2.ClassRoom = t1.ClassRoom
AND NOT EXISTS (SELECT 1 FROM tableA t3
WHERE t3.EndTime < t2.EndTime
AND t3.EndTime > t1.EndTime
AND (t3.CourseName <> t2.CourseName
OR t3.ClassRoom <> t2.ClassRoom)
)
) EndTime
FROM tableA t1
) t0 GROUP BY t0.ClassRoom, t0.CourseName, t0.EndTime
http://www.sqlfiddle.com/#!6/39d4b/9
Group rows if certain column value directly after another in SQL
If id
s are one after one try do it this way:
select * into #tab from(
select 0 as id, 'bob' as name, 'note' as event, '14:20' as time union
select 1, 'bob', 'time', '14:22' union
select 2, 'bob', 'time', '14:40' union
select 3, 'bob', 'time', '14:45' union
select 4, 'bob', 'send', '14:48' union
select 5, 'bob', 'time', '15:30' union
select 6, 'bob', 'note', '15:35' union
select 7, 'bob', 'note', '18:00'
) t
select t.*
from #tab t
left join #tab t1 on t.id = t1.id + 1 and t1.event = t.event
-- and t1.name = t.name -- if there are more names you are going to need this one as well
where t1.id is null
result:
id name event time
0 bob note 14:20
1 bob time 14:22
4 bob send 14:48
5 bob time 15:30
6 bob note 15:35
Added:
If id
s aren't one after one, you can make them to be:
select identity(int, 1, 1) as id, name, event, time
into #tab_ordered_ids
from #tab order by name, id, time
Creating Columns in a View That Use an Aggregate Method in a Case...When Expression
You need to put your case
inside your sum
:
SUM(CASE WHEN kth.[Portfolio Report Category] = '705' THEN TRY_CONVERT(money, kth.[Market Value]) ELSE '0.00' END) AS [Crypto Total Value],
Here is a working example:
declare @Adr table ([Account Number] varchar(6), [Account_ Display Name] varchar(64), [Account Category Code] varchar, [Division Code] varchar, [Division Name] varchar, [Market Value Amount] money);
declare @Kth table ([Account Number] varchar(6), [Portfolio Report Category] varchar(3), [Market Value] money);
declare @Ktc table ([Account Number] varchar(6), [Available Cash Amount] money);
insert into @Adr ([Account Number], [Account_ Display Name])
values ('001000', 'Carl S Sykes Roth IRA');
insert into @Kth ([Account Number], [Market Value], [Portfolio Report Category])
values ('001000', 9998.4792, '600'),
('001000', 43467.09, '600'),
('001000', 84524.71, '600');
insert into @Ktc ([Account Number])
values ('001000');
SELECT adr.[Account Number], adr.[Account_ Display Name], adr.[Account Category Code], adr.[Division Code], adr.[Division Name], adr.[Market Value Amount]
, SUM(CASE WHEN kth.[Portfolio Report Category] = '705' THEN (TRY_CONVERT(money, kth.[Market Value])) ELSE 0 END) AS [Crypto Total Value]
, SUM(CASE WHEN kth.[Portfolio Report Category] = '691' THEN (TRY_CONVERT(money, kth.[Market Value])) ELSE 0 END) AS [Precious Metal Total Value]
, SUM(CASE WHEN kth.[Portfolio Report Category] IN ('010', '011', '020', '025', '030') THEN (TRY_CONVERT(money, kth.[Market Value])) ELSE 0 END) AS [Stock Total Value]
, SUM(CASE WHEN kth.[Portfolio Report Category] NOT IN ('010', '011', '020', '025', '030', '691', '705') THEN (TRY_CONVERT(money, kth.[Market Value])) ELSE 0 END) AS [Other Total Value]
, ktc.[Available Cash Amount] AS [CASH TOTAL]
FROM @Adr adr
INNER JOIN @Kth kth ON adr.[Account Number] = kth.[Account Number]
INNER JOIN @Ktc ktc ON adr.[Account Number] = ktc.[Account Number]
GROUP BY adr.[Account Number], adr.[Account_ Display Name], adr.[Account Category Code], adr.[Division Code], adr.[Division Code], adr.[Division Name], adr.[Market Value Amount], ktc.[Available Cash Amount];
Which returns (un-necessary columns removed):
Account Number Crypto Total Value Precious Metal Total Value Stock Total Value Other Total Value CASH TOTAL
001000 0.00 0.00 0.00 137990.2792 NULL
Edit: As you have now added sample data, the reason you were getting incorrect values is because you had duplicate rows in your KTAccountsADR
which then multiple the rows in the KTHoldings
table. Resolve the duplicates and you will get the correct values when using case
inside sum
.
Note, its best practice to ensure you are returning the same datatype from all branches of a case
expression.
Related Topics
Powershell SQL Select Output to Variable
Create Temp Table with Range of Numbers
Can You Have a Foreign Key Onto a View of a Linked Server Table in SQLserver 2K5
Insert Manually into a Table by SQL Statement, But Key Is Autoincremented
Get Latest Id from a Duplicate Records in a Table
Go with SQL Server Driver Is Unable to Connect Successfully, Login Fail
Using Variables in Classic Asp Parameterized SQL
Postgres Drop Table Syntax Error
How to Use Group by on a Clob Column with Oracle
Insert Combine (Value and Select)
Oracle 10G Express Home Page Is Not Coming Up
Preserve Parent-Child Relationships When Copying Hierarchical Data
Creating Sumif Function in SQL Server 2012