So for a table like this i want to have another column which has the reqd_col value if cond_value is > 100 and to take the previous value in other cases.
User
cond_Value
Reqd_Col
123456
159
12:30
123456
34
12:32
123456
46
12:35
123456
98
12:37
123456
123
12:56
123456
12
13:00
789000
100
16:00
789000
54
16:10
789000
23
16:14
789000
122
17:05
789000
98
17:08
789000
133
17:23
So the output should look like
User
cond_Value
Reqd_Col
Output
123456
159
12:30
12:30
123456
34
12:32
12:30
123456
46
12:35
12:30
123456
98
12:37
12:30
123456
123
12:56
12:56
123456
12
13:00
12:56
789000
100
16:00
16:00
789000
54
16:10
16:00
789000
23
16:14
16:00
789000
122
17:05
17:05
789000
98
17:08
17:05
789000
133
17:23
17:23
Ideally i would like to have this as a view in BigQuery.
Try below query.
SELECT *, LAST_VALUE(IF(cond_Value >= 100, Reqd_Col, NULL) IGNORE NULLS) OVER w AS Output
FROM sample_table
WINDOW w AS (PARTITION BY User ORDER BY PARSE_TIME('%R', Reqd_Col))
ORDER BY 1, 3;
+--------+------------+----------+--------+
| User | cond_Value | Reqd_Col | Output |
+--------+------------+----------+--------+
| 123456 | 159 | 12:30 | 12:30 |
| 123456 | 34 | 12:32 | 12:30 |
| 123456 | 46 | 12:35 | 12:30 |
| 123456 | 98 | 12:37 | 12:30 |
| 123456 | 123 | 12:56 | 12:56 |
| 123456 | 12 | 13:00 | 12:56 |
| 789000 | 100 | 16:00 | 16:00 |
| 789000 | 54 | 16:10 | 16:00 |
| 789000 | 23 | 16:14 | 16:00 |
| 789000 | 122 | 17:05 | 17:05 |
| 789000 | 98 | 17:08 | 17:05 |
| 789000 | 133 | 17:23 | 17:23 |
+--------+------------+----------+--------+
I want to add a new column on my SQL query that will count the number of times a value on the row appears in a different table.
For example, let's say I have these two separate tables.
Table Name: Table_A
Id | Coach | Team_Color | Team_Number
------------------------------------------
001 | Jane | Orange | 121
002 | Frank | Purple | 232
003 | Tim | Red | 343
Table Name: Table_B
Id | Team_Number | Player_Name
----------------------------------
901 | 121 | Jimmy
902 | 121 | Wesley
903 | 121 | Samantha
904 | 121 | Wendy
905 | 232 | Tim
906 | 232 | Sean
907 | 343 | Andrew
908 | 343 | Erik
909 | 343 | Sarah
910 | 343 | Allison
911 | 343 | Desmond
912 | 343 | Kathryn
I want to end up with something like this:
Id | Coach | Team_Color | Team_Number | Player Count
--------------------------------------------------------
001 | Jane | Orange | 121 | 4
002 | Frank | Purple | 232 | 2
003 | Tim | Red | 343 | 6
The new column called "Player Count" is referencing the Team_Number value in Table_A, and counting the number of instances found on Table_B. How would I compose this into one query?
Solution to your Problem:
SELECT A.Id, A.Coach, A.Team_Color,A.Team_Number,Count(B.Id) AS Player_Count
FROM Table_A AS A
INNER JOIN Table_B B
ON A.Team_Number = B.Team_Number
GROUP BY A.Id, A.Coach, A.Team_Color,A.Team_Number;
OUTPUT:
Id Coach Team_Color Team_Number Player_Count
1 Jane Orange 121 4
2 Frank Purple 232 2
3 Tim Red 343 6
Follow the link to the demo:
http://sqlfiddle.com/#!9/9c6da4/1
EXPLAINATION:
In your problem, you have to use JOIN to join the two tables on a common Column i.e.Team_Number. Now after Joining you will get a result like this:
Id Coach Team_Color Team_Number Id Team_Number Player_Name
1 Jane Orange 121 901 121 Jimmy
1 Jane Orange 121 902 121 Wesley
1 Jane Orange 121 903 121 Samantha
1 Jane Orange 121 904 121 Wendy
2 Frank Purple 232 905 232 Tim
2 Frank Purple 232 906 232 Sean
3 Tim Red 343 907 343 Andrew
3 Tim Red 343 908 343 Erik
3 Tim Red 343 909 343 Sarah
3 Tim Red 343 910 343 Allison
3 Tim Red 343 911 343 Desmond
3 Tim Red 343 912 343 Kathryn
Now Use aggregate function COUNT on above Result to get the final result.
Followed by my previous question on finding the increasing subsequence in a data set.
Finding out the increasing subsequence in sql
To obtain the result
x | y
-----+-----
94 | 985
469 | 865
525 | 842
610 | 587
765 | 579
from
x | y
-----+-----
94 | 985
73 | 940
469 | 865
115 | 864
366 | 862
525 | 842
448 | 837
318 | 832
507 | 826
244 | 758
217 | 741
207 | 732
54 | 688
426 | 605
108 | 604
610 | 587
142 | 581
765 | 579
102 | 572
I can apply the query
select x, y
from (select max(x) over (order by y desc) as x_max, x, max(y) over (order by x desc) as y_max, y
from table
order by y desc, x desc) t
where t.x = t.x_max and t.y = t.y_max
order by y desc, x
Now my question is, how can I perform this operation n times, i.e. finding the 2nd, 3rd, ..., nth increasing subsequence of x.
I know the general idea is to take the result of the first operation from the original table and perform the the query on the remaining points.
So in my example, after the first operation, we have the remaining points,
x | y
-----+-----
73 | 940
115 | 864
366 | 862
448 | 837
318 | 832
507 | 826
244 | 758
217 | 741
207 | 732
54 | 688
426 | 605
108 | 604
142 | 581
102 | 572
and apply the query again, we get
x | y
-----+-----
73 | 940
115 | 864
366 | 862
448 | 837
507 | 826
And perform the operation on
x | y
-----+-----
318 | 832
244 | 758
217 | 741
207 | 732
54 | 688
426 | 605
108 | 604
142 | 581
102 | 572
so on and so forth. I would also like to union all the points from these query searches and order them by y desc, i.e.
x | y
-----+-----
73 | 940
94 | 985
115 | 864
366 | 862
448 | 837
469 | 865
507 | 826
525 | 842
610 | 587
765 | 579
This is not trivial & far from optimal, but you can indeed do this with recursive CTEs:
with recursive r as(
(select x, y, (running_x_max <> x)::int grp, 0 iteration
from (select *, max(x) over (order by y desc) running_x_max
from xy) t
order by 3, 2 desc)
union all
(select x, y, grp + (running_x_max <> x)::int, iteration + 1
from (select *, max(x) over (order by y desc) running_x_max
from r
where grp > iteration) t
order by 3, 2 desc)
)
select x, y, grp
from r
where grp = iteration
order by 3, 2 desc, 1
http://rextester.com/JDYJ58330
So i have a table containing below columns.
I want to compute an running average from positiondate and for example 3 days back, grouped on dealno.
I know how to do with "case by" but problem is that I have around 200 different DealNo so I do not want to write an own case by clause for every deal.
On dealNo 1 it desired output should be Average(149 243 440 + 149 224 446 + 149 243 451)
DealNo PositionDate MarketValue
1 | 2016-11-27 | 149 243 440
2 | 2016-11-27 | 21 496 418
3 | 2016-11-27 | 32 249 600
1 | 2016-11-26 | 149 243 446
2 | 2016-11-26 | 21 496 418
3 | 2016-11-26 | 32 249 600
1 | 2016-11-25 | 149 243 451
3 | 2016-11-25 | 32 249 600
2 | 2016-11-25 | 21 496 418
3 | 2016-11-24 | 32 249 600
1 | 2016-11-24 | 149 225 582
2 | 2016-11-24 | 21 498 120
1 | 2016-11-23 | 149 256 867
2 | 2016-11-23 | 21 504 181
3 | 2016-11-23 | 32 253 440
1 | 2016-11-22 | 149 256 873
2 | 2016-11-22 | 21 506 840
3 | 2016-11-22 | 32 253 440
1 | 2016-11-21 | 149 234 535
2 | 2016-11-21 | 21 509 179
3 | 2016-11-21 | 32 253 600
I tried below script but it was not very effective since my table contains around 300k rows and approx 200 different dealno.
Is there a more effective way to do this in SQL 2008?
with cte as (
SELECT ROW_NUMBER() over(order by dealno, positiondate desc) as Rownr,
dealno,
positiondate,
Currency,
MvCleanCcy
FROM T1
)
select
rownr, positiondate, DealNo, Currency,
mvcleanavg30d = (select avg(MvCleanCcy) from cte2 where Rownr between c.Rownr and c.Rownr+3)
from cte as c
You don't need window functions. You can do this using outer apply:
select t1.*, tt1.marketvalue_3day
from t1 outer apply
(select avg(tt1.marketvalue) as marketvalue_3day
from (select top 3 tt1.*
from t1 tt1
where tt1.deal1 = t1.deal1 and
tt1.positiondate <= t1.positiondate
order by tt1.positiondate desc
) tt1
) tt1;
So my data looks like this:
+-----------+---------+-------------+-------+-------------+--+
| time | Outlets | Meal_Period | cover | day_of_week | |
+-----------+---------+-------------+-------+-------------+--+
| 10/1/2013 | 72 | 1 | 0 | Tuesday | |
| 10/1/2013 | 72 | 2 | 31 | Tuesday | |
| 10/1/2013 | 72 | 3 | 116 | Tuesday | |
| 10/1/2013 | 72 | 6 | 32 | Tuesday | |
| 10/1/2013 | 187 | 17 | 121 | Tuesday | |
| 10/1/2013 | 187 | 18 | 214 | Tuesday | |
| 10/1/2013 | 187 | 19 | 204 | Tuesday | |
| 10/1/2013 | 101 | 2 | 0 | Tuesday | |
| 10/1/2013 | 101 | 3 | 0 | Tuesday | |
| 10/1/2013 | 101 | 4 | 0 | Tuesday | |
| 10/1/2013 | 101 | 6 | 0 | Tuesday | |
| 10/1/2013 | 282 | 1 | 17 | Tuesday | |
| 10/1/2013 | 282 | 2 | 207 | Tuesday | |
| 10/1/2013 | 282 | 3 | 340 | Tuesday | |
| 10/1/2013 | 282 | 6 | 4 | Tuesday | |
| 10/1/2013 | 103 | 1 | 0 | Tuesday | |
+-----------+---------+-------------+-------+-------------+--+
The code is:
IF OBJECT_ID('tempdb.dbo.#time') IS NOT NULL
DROP TABLE #time
SELECT DATEADD(dd, 0, DATEDIFF(DD, 0, open_dttime)) AS 'time'
,profit_center_id AS 'Outlets'
,meal_period_id AS 'Meal_Period'
,sum(num_covers) AS 'Number_Covers'
INTO #time
FROM [STOF_Infogen].[dbo].[Order_Header]
WHERE CasinoID = 'csg'
AND profit_center_id IN (
'102'
,'100'
,'283'
,'101'
,'282'
,'187'
,'280'
,'103'
,'281'
,'72'
,'183'
)
AND (
open_dttime BETWEEN '2014-02-01 06:30'
AND '2014-03-01 06:30'
)
GROUP BY profit_center_id
,open_dttime
,meal_period_id
ORDER BY profit_center_id
,meal_period_id
IF OBJECT_ID('tempdb.dbo.#time2') IS NOT NULL
DROP TABLE #time2
SELECT [TIME]
,Outlets AS 'Outlets'
,meal_period AS 'Meal_Period'
,SUM(number_covers) AS 'cover'
,DATENAME(DW, [time]) AS 'day_of_week'
INTO #time2
FROM #time
GROUP BY [TIME]
,Outlets
,Meal_Period
ORDER BY [TIME] ASC
,Outlets
,Meal_Period
SELECT *
FROM #time2
I created temporary drop tables for my date but I'm having two issues;
I will like to group where the profit centres are 187 and 282 while still keeping the other rows.
for some reason I can't tweek the date stamp because it excludes the last day of the month.
As always any help is appreciated.
Making some test data:
DECLARE #MealInfo TABLE
(
MealTime DATETIME,
Outlets VARCHAR(10),
Meal_Period int,
Cover INT
)
INSERT INTO #MealInfo
VALUES
('10/1/2013', '72', 1, 0),
('10/1/2013', '72', 2, 31),
('10/1/2013', '72', 3, 116),
('10/1/2013', '72', 6, 32),
('10/1/2013', '187', 17, 121),
('10/1/2013', '187', 18, 214),
('10/1/2013', '187', 19, 204),
('10/1/2013', '101', 2, 0),
('10/1/2013', '101', 3, 0),
('10/1/2013', '101', 4, 0),
('10/1/2013', '101', 6, 0),
('10/1/2013', '282', 1, 17),
('10/1/2013', '282', 2, 207),
('10/1/2013', '282', 3, 340),
('10/1/2013', '282', 6, 4),
('10/1/2013', '103', 1, 0);
Because you want to group 187 and 282 together, I use a case statement to lump them into one outlet and then we can group on the outlets to break out the sums:
SELECT
m.MealTime,
m.Outlets,
m.Meal_Period,
SUM(m.Cover) AS Number_Covers
FROM
(
SELECT mi.MealTime,
(CASE WHEN mi.Outlets IN ('187', '282') THEN '187+282' ELSE mi.Outlets END) Outlets,
mi.Meal_Period,
mi.Cover
FROM #MealInfo mi
) m
GROUP BY m.MealTime, m.Outlets, m.Meal_Period
Here is the output:
MealTime Outlets Meal_Period Number_Covers
2013-10-01 00:00:00.000 101 2 0
2013-10-01 00:00:00.000 101 3 0
2013-10-01 00:00:00.000 101 4 0
2013-10-01 00:00:00.000 101 6 0
2013-10-01 00:00:00.000 103 1 0
2013-10-01 00:00:00.000 187+282 1 17
2013-10-01 00:00:00.000 187+282 2 207
2013-10-01 00:00:00.000 187+282 3 340
2013-10-01 00:00:00.000 187+282 6 4
2013-10-01 00:00:00.000 187+282 17 121
2013-10-01 00:00:00.000 187+282 18 214
2013-10-01 00:00:00.000 187+282 19 204
2013-10-01 00:00:00.000 72 1 0
2013-10-01 00:00:00.000 72 2 31
2013-10-01 00:00:00.000 72 3 116
2013-10-01 00:00:00.000 72 6 32
If your data had overlapping periods for 187 and 282, the sum total would contain both parts into 1 column.