This question already has answers here:
Filter rows in a column based on set rules in SQL
(2 answers)
Closed 1 year ago.
Group ID Values Month
1 09239820 43 May
2 2872498938 23 Jan
2 1267 18 Dec
3 23219823983 09 Sept
3 267839236 11 July
4 33287442 23 Jan
I want to replace the 1st, 2nd and 4th numbers in the ID column with letters
Replace 1st with N
Replace 2nd with X
Replace 4TH with D
Expected output:
Group ID Value Month
1 NX2D9820 43 May
2 NX7D498938 23 Jan
2 NX6D 18 Dec
3 NX2D9823983 09 Sept
3 NX7D39236 11 July
4 NX2D7442 23 Jan
I am new to SQL, and I have written the following code below (it is not working)
SELECT * FROM #table# t1;
UPDATE t1 SET ID = CONCAT('NX', SUBSTRING(ID,3,1), 'D', SUBSTRING(ID,5));
SELECT * FROM t1;
I found a way of doing this task, maybe it is not the simplest and fastest one but it make sense. If somebody think of any improvement on the query, feel free to edit my answer.
UPDATE test_01 tbl1
INNER JOIN (
select `group`, concat_ws('',substring(RIGHT((insert(id, 1, 2, 'NX')), 9999),1,3), substring(LEFT((insert(id, 4, 1, 'D')), 9999),4,9999)) as id_tbl2
from test_01)
as tbl2
ON tbl1.`group` = tbl2.`group`
SET tbl1.id = tbl2.id_tbl2;
Working demo:https://www.db-fiddle.com/f/7yUJcuMJPncBBnrExKbzYz/6
Let me explain what the query does
insert(id, 1, 2, 'NX') ---> inserts NX in first and second place
insert(id, 4, 1, 'D' ---> inserts D in the fourth place
substring(RIGHT((insert(id, 1, 2, 'NX')), 9999),1,3) ---> select
first three characters changed
substring(LEFT((insert(id, 4, 1, 'D')), 9999),4,9999) ---> select from the fourth character to the end
of the row because 9999 extends the column limit
Using concat_ws I combine tha changed data to a new table and in the
end we can update using the join condition.
I am trying to find values between a range from 2 different col.
Below is the structure of my table :
OBJECT FIELD LOW HIGH
----------------------------
S_IDOCMONI ACTVT 01 03
I wanted to search for values 01, 02 and 03 between cols LOW and HIGH. Currently i have written a CASE statement only to check in col LOW :
select *
into [abc]
from
(select
*,
case
when [OBJECT] = 'S_IDOCCTRL' and [FIELD] = 'ACTVT' and [LOW] in ('01')
then '1'
end [Subgroup]
from
[user-master]) as x
where
subgroup is not null
Could anyone help me where I can search for value 02 (as a range between cols. LOW and HIGH)
There's two table in my database:
Table A
Column_A1 column_A2
A1 10
A2 20
A3 30
Table B
Column_B1 column_B2
B1 11
B2 21
B3 31
B4 29
I want to calculate how many row of table B match the following condition:
range:
A1±1,
A2±1,
A3±1,
...
for example:
B1∈[A1-1,A1+1]
count these row, return value 1.
B2∈[A2-1,A2+1]
count these row, return value 1.
B3∈[A3-1,A3+1]
B4∈[A3-1,A3+1]
count these row, return value 2.
Result should be like this:
Column_A1 column_A2 num_match
A1 10 1
A2 20 1
A3 30 2
It's easy to use a loop to do this in other programming language, but what's the simplest way to make it in MySQL ? Thanks.
Try like this:
SELECT table_a.Column_A1, table_a.Column_A2, count(table_b.Column_B2) as num_match
FROM table_a
LEFT JOIN (SELECT * FROM table_b) AS table_b
ON table_a.Column_A2 = table_b.Column_B2 - 1 OR table_a.Column_A2 = table_b.Column_B2 + 1;
Input
Table 1:
CountryCode is_holiday ? TicketsRaiseDay NofTickets TotalTickets
91 No Mon 10 10
91 No Tue 20 20
91 Yes Sat 10 NA (since it is holiday )
91 No Mon 5 15 (Sat tickets +Monday Tickets )
Here totaltickets column is calculated or computed column or report column .
Note : is_holiday column is the responsible to hold holiday detail so need not to bother about this field .
It would be great if i can get either ssrs expression or sql code .
This should do the trick:
You can see a working example here.
SELECT
x.countrycode,
x.is_holiday,
case when x.previousHoliday = 1 THEN previousNumberOfTickets + x.nofTickets
when x.is_holiday = 1 then 0
else x.nofTickets
end
from (select
is_holiday,
nofTickets,
countrycode,
lag(is_Holiday,1) over (order by countrycode) as previousHoliday,
lag(nofTickets,1) over (order by countrycode) as previousNumberOfTickets
from tickets) x
Note: this doesn't handle consecutive holidays. Also, you would probably want to order by something other than countrycode. I wasn't sure what you're ordering by.
Edit: I just noticed you're using sql server 2008, and the lag function is not available until 2012.
I have a MySQL query:
SELECT px.player, px.pos, px.year, px.age, px.gp, px.goals, px.assists
, 1000 - ABS(p1.gp - px.gp) - ABS(p1.goals - px.goals) - ABS(p1.assists - px.assists) sim
FROM hockey p1
JOIN hockey px
ON px.player <> p1.player
WHERE p1.player = 'John Smith'
AND p1.year = 2010
HAVING sim >= 900
ORDER BY sim DESC
This gets me a table of results, something like this:
player pos year age gp goals assists sim
Player1 LW 2002 25 75 29 32 961
Player2 LW 2000 27 82 29 27 956
Player3 RW 2000 27 78 29 33 955
Player4 LW 2009 26 82 30 30 940
Player5 RW 2001 25 79 33 24 938
Player6 LW 2008 25 82 23 24 936
Player7 LW 2006 27 79 26 33 932
Instead, I would like it to do two things. Average the data and add a player count, so I get something like:
players age gp goals assists sim
7 26 79 28 29 945
I tried avg(px.age), avg(px.gp), avg(px.goals)...etc but I am running into errors with my "sim" formula.
Second issue is that underneath that, I would like to have the average of the data for the FOLLOWING year. In other words data from Player1 in 2003, data from Player2 in 2001, etc.
I am stuck as to HOW to get the data to average AND to get it for the following year.
Can anyone help me with either or both of these issues?
To get a single subtotal of counts and averages, just wrap your original query AS the inner select... something like... (pq = "PreQuery" select result)
Select
max( "Tot Players" ) Players,
max( "->" ) position,
count(*) Year,
avg( pq.age ) AvgAge,
avg( pq.gp ) AvgGP,
avg( pq.goals ) AvgGoals,
avg( pq.assists ) AvgAssists,
avg( pq.sim ) AvgSim
from
( SELECT
px.player,
px.pos,
px.year,
px.age,
px.gp,
px.goals,
px.assists,
1000 - ABS(p1.gp - px.gp)
- ABS(p1.goals - px.goals)
- ABS(p1.assists - px.assists) sim
FROM
hockey p1
JOIN hockey px ON px.player <> p1.player
WHERE
p1.player = 'John Smith'
AND p1.year = 2010
HAVING
sim >= 900
ORDER BY
sim DESC ) pq
If your original query worked, this should get you your overall averages. However, with the INNER query with a having and order, might cause a problem. You might need to kill the order by since it really makes no difference in the outer most query. As for the HAVING clause in the INNER query, might need to be moved to a WHERE pq.sim >= 900 in the OUTER SQL-Select.
Additionally, if you wanted the results of all players first, THEN the total, take your original query and merge it with this one... As you'll see, to keep the columns in synch with BOTH queries, I've put a bogus for player and position so it won't crash on mismatched unions... Notice my COUNT column actually would correspond with the YEAR column of the ORIGINAL query.
For the prior year... As Rob mentioned, you would just do a UNION of the two queries just showing the respective year you were qualifying for in each UNION...
EDIT --- CLARIFICATION for 2nd YEAR....
Per your subsequent comment clarification, you would have to get the basis as the basis of the year +1... if you then want the overall averages again, those would be wrapped to an outer max / avg, etc... But I think THIS is what you want for the subsequent year per player
SELECT
PrimaryQry.PrimaryPlayer,
PrimaryQry.PrimaryPos,
PrimaryQry.PrimaryYear,
PrimaryQry.PrimaryAge,
PrimaryQry.PrimaryGP,
PrimaryQry.PrimaryGoals,
PrimaryQry.PrimaryAssists,
PrimaryQry.player,
PrimaryQry.pos,
PrimaryQry.year,
PrimaryQry.age,
PrimaryQry.gp,
PrimaryQry.goals,
PrimaryQry.assists,
PrimaryQry.sim,
p2.pos PrimaryPos2,
p2.year PrimaryYear2,
p2.age PrimaryAge2,
p2.gp PrimaryGP2,
p2.goals PrimaryGoals2,
p2.assists PrimaryAssists2,
px2.player player2,
px2.pos pos2,
px2.year year2,
px2.age age2,
px2.gp gp2,
px2.goals goals2,
px2.assists assists2,
1000 - ABS(p2.gp - px2.gp)
- ABS(p2.goals - px2.goals)
- ABS(p2.assists - px2.assists) sim2
FROM
( SELECT
p1.player PrimaryPlayer,
p1.pos PrimaryPos,
p1.year PrimaryYear,
p1.age PrimaryAge,
p1.gp PrimaryGP,
p1.goals PrimaryGoals,
p1.assists PrimaryAssists,
px.player,
px.pos,
px.year,
px.age,
px.gp,
px.goals,
px.assists,
1000 - ABS(p1.gp - px.gp)
- ABS(p1.goals - px.goals)
- ABS(p1.assists - px.assists) sim
FROM
hockey p1
JOIN hockey px
ON p1.player <> px.player
WHERE
p1.player = 'John Smith'
AND p1.year = 2010
HAVING
sim >= 900 ) PrimaryQry
JOIN hockey p2
ON PrimaryQry.PrimaryPlayer = p2.player
AND PrimaryQry.PrimaryYear +1 = p2.year
JOIN hockey px2
ON PrimaryQry.Player = px2.Player
AND PrimaryQry.Year +1 = px2.year
If you follow the logic here, you already know the inner query is returning about 10 other players. So, I am keeping the stats of the first person basis IN that query too. THEN, I am joining that result set back to the hockey table TWICE... The join is primary player joined to the first for his/her year +1, the SECOND join works specifically to the one person that qualified against the primary player. The final column results get the entire first year qualifier with the second qualifier, such as
So, it will all be on one row consecutively of
John Smith 2010 Compare Person 1 YearA John Smith 2011 Compare Person 1 YearA+1
John Smith 2010 Compare Person 2 YearB John Smith 2011 Compare Person 2 YearB+1
John Smith 2010 Compare Person 3 YearC John Smith 2011 Compare Person 3 YearC+1
What query are you using to get the averages?
Just applying "AVG" to your expression for 'sim' should work in mysql. e.g.
AVG(1000 - ABS(p1.gp - px.gp) - ABS(p1.goals - px.goals) - ABS(p1.assists - px.assists)) sim
To aggregate over different years, I think there is no alternative to using a subselect or union.
Reference:
http://dev.mysql.com/doc/refman/5.0/en/subqueries.html
http://dev.mysql.com/doc/refman/5.0/en/union.html
Something like:
(ORIGINAL AVG QUERY)
UNION ALL
(ORIGINAL AVG QUERY WITH NEW YEAR)
should do the trick.
(Note that your original query selects data from every year to compare it to the data for John Smith in 2010, which may not be what you want.)