SQL Server Pivot Ordering issue - sql-server-2008

my query returns a pivot table, the first column (nummnth) contain text values like 01,02,03 for the months Jan, Feb, Mar. The problem is that the ordering is 01 , 03 , 02 Instead of 01,02,03.
How could i fix this ???
the query is:
select [nummnth] ,[mnth],[Business Fixed Score],[Business Fixed
Sessions],[Business Mobile Score],[Business Mobile Sessions],[Business
Merged Score],[Business Merged Sessions] from (Select [nummnth],
[Mnth],C.* from (
SELECT [Service],nummnth,mnth,b.A2 as [User_Score],b.A2_Sessions as
[Sessions_Count] FROM [QTDB].[dbo].[QTD_BOX_BUS_MERGED_CP] as [b] where
YR=2017
and [service] = 'Business Fixed' and Agent='ANAME'
Union
SELECT [Service],nummnth,mnth,b.A2 as [User_Score],b.A2_Sessions as
[Sessions_Count]
FROM [QTDB].[dbo].[QTD_BOX_BUS_MERGED_CP] as [b] where YR=2017 and
[service] = 'Business Mobile' and Agent='ANAME'
UNION all
SELECT 'Business Merged' as [Service] ,nummnth,mnth,b.A2 as
[User_Score],b.A2_Sessions as [Sessions_Count]
FROM [QTDB].[dbo].[QTD_BOX_BUS_AGENT_MNTH_MERGED] as [b] where YR=2017
and Agent='ANAME') A
Cross Apply (Values (A.[Service]+' Score',
cast(A.[User_Score] as float)),(A.[Service]+' Sessions',cast(A.
[Sessions_Count] as float))) C (Item,Value)) R Pivot (
sum(Value) For [Item] in ([Business Fixed Score],
[Business Fixed Sessions],
[Business Mobile Score],[Business Mobile Sessions],
[Business Merged Score],[Business Merged Sessions])) PV

In SQL-Server there is no implicit order!! None, never...
You cannot even say The problem is that the ordering is 01 , 03 , 02 Instead of 01,02,03. The next call it might return differently.
The only way to ensure the order is ORDER BY on the outermost query!
Just add ORDER BY [nummnth] as last line and check the result.

Related

Changing field fill of max value in column groups on SSRS 2014

I have a table in SSRS that has both row and column groups.
For each row group [Cat], I need to highlight the highest value in the column group, which is the sum of all counts for that category in a given month.
Can't for the life of me figure it out, so if anyone could help that would be great!
Thanks
Example of dataset
This is what I'm aiming for
Table in Design View
Current outcome
The problem you will face is that you will have to try to use nested aggregates with scopes defined. This might be possible (but I don't think it is...)
There is a fairly simple way to fix it though. I can;t give an exact answer as I don;t know what your dataset looks like but typically you would have to make some changes to your dataset, then its simple.
So assuming your dataset looks something like this
Cat myDate counts
A 20171001 90
A 20171001 6
B 20171001 18
C 20171001 1
A 20171101 100
A 20171101 20
....
....
Then aggregate everything so the report does not have to do any real aggregation with something like
SELECT
*
, max(counts) OVER(PARTITION BY Cat) as maxInCat
FROM (
SELECT
Cat, myDate
, SUM(counts) as counts
FROM myTable
GROUP BY Cat, myDate
) x
This will give you a dataset with an additional column maxInCat. This column will contain the maximum value in each category so we can compare against this in the report.
The expression can then be something like
=IIF(SUM(Fields!counts.Value)>0 and SUM(Fields!counts.Value) = Fields!maxInCat.Value, "Yellow", Nothing)
EDIT
I've updated the actual backcolor expression as it didn't account for blanks/zeros
Ignoring the fact the the columns are not sorted as I don't have time, here's the result
Here's an answer that I think does what you need:
declare #Table as table
(
[Cat] char(1),
[Sector] tinyint,
[Counts] int,
[Date] date
);
insert into #Table
(
[Cat],
[Sector],
[Counts],
[Date]
)
values
('A', 1, 4103, '2017-10-01'),
('A', 1, 3001, '2017-11-01'),
('A', 1, 1128, '2017-12-01'),
('A', 1, 5917, '2018-01-01'),
('A', 1, 9594, '2018-02-01'),
...
So you know where the data is coming from.
with [AggregatedData] as
(
select
t.Cat,
t.Sector,
t.Counts,
t.[Date],
sum(t.Counts) over (partition by t.Cat, t.[Date]) as [SumCounts]
from #Table as [t]
)
select
ad.Cat,
ad.Sector,
ad.Counts,
ad.[Date],
ad.SumCounts,
max(ad.SumCounts) over (partition by ad.[Date]) as [MaxSumCounts]
from [AggregatedData] as [ad]
Then in SSRS, you can use:
=iif(IsNothing(Fields!SumCounts.Value) = FALSE AndAlso Fields!SumCounts.Value = Fields!MaxSumCounts.Value, "Yellow", "Transparent")
Which gives:

How to get distinct records but on base on first 2 digits only in MySQL

I want to get distinct records (only one field) from a MySQL table, and that field contain only digits.
Example:
00010000
01111100
01112000
01118000
02301201
But distinct records is considered on base on first 2 digits. So in the case above, I need to get back only 3 records:
00010000
01112000
02301201
More over, I would like to trim the rest of the digits, so the actual end result should be:
00
01
02
So distinct and group by will not cut here. Any idea?
Assuming you wanted the least value from among duplicates, you could try:
SELECT t1.col
FROM yourTable t1
INNER JOIN
(
SELECT LEFT(col, 2) AS prefix, MIN(col) AS min_col
FROM yourTable
GROUP BY LEFT(col, 2)
) t2
ON LEFT(t1.col, 2) = t2.prefix AND
t1.col = t2.min_col;
Note: Numbers in MySQL don't start with zeroes, so your requirement (and this answer) only make sense if your column is text.
DISTINCT will work fine with LEFT to give the results you want:
SELECT DISTINCT(LEFT(value, 2)) AS value
FROM data
ORDER BY value
Output
00
01
02
Demo on dbfiddle
If you only want the trimmed value, try this:
SELECT SUBSTRING(yourColumn,1,2) as trimmedval
FROM Table
GROUP BY SUBSTRING(yourColumn,1,2)

Mysql joining two tables where part of string in table1 are in table2

I am currently developing an employee database website. Previously my client use ms. excel as database storage which has no structure. But they already have thousands of data. I have already imported data into temporary tables. The problem is, I had to adjust the excel data with database structure.
This is my tables structure :
ms_absen :
id name
------------------------
11 vnice ardian
22 setiawan ecco
33 andytaman1
44 rusdytaman2
ms_employee :
id_emp name
---------------------------
01 ardiansyah
02 setiawan thea
03 arif andy syah
04 jonathan
05 f rusdy
expected result :
id_emp name id
--------------------------------------
01 ardiansyah 11
02 setiawan thea 22
03 arif andy syah 33
05 rusdy 44
This is what I have tried so far,
select e.id_emp,e.name,a.id
from ms_employee as e
inner join ms_absen a
on a.name like concat('%',left(e.name,3),'%')
This return only ardiansyah, setiawan thea and rusdy instead of all employees except jonathan. Please note that I use inner join rather than left join, because I want to eliminated employes that not in ms_absen table.
You can't map one thing to another ( or join in your state ) without having a mapping ).
If I were you I would try to map one of the tables to other table with good data and then apply something like you've specified
select e.id_emp,e.name,a.id
from ms_employee as e
inner join ms_absen a
on a.name like concat('%',left(e.name,3),'%')
Question is - how to transform your data into good one?
You see, you have a spaces in this name column. And if you had no spaces, then it would be easier. So you map one table to some transition table with columns id, name_part1, name_part2, ..., name_partN, where N is the maximum number of words in name ( finding this N can be done manually ). Then you can apply logic alike this one (this is the comment to MySQL documentation on string built-in functions):
// Posted by [name withheld] on March 22 2006 8:02pm
// This will split an IP address ("a.b.c.d") into 4 respective octets:
SELECT
`ip` ,
SUBSTRING_INDEX( `ip` , '.', 1 ) AS a,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', 2 ),'.',-1) AS b,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', -2 ),'.',1) AS c,
SUBSTRING_INDEX( `ip` , '.', -1 ) AS d
FROM log_table
Thus you will have a table where every column nameX where X is inside range 1...N.
This is the best I can suggest you for now without using RDBMS )
Given we have data presented in the question we can write something like this:
This will result in a table with 3 columns. Let's assume the resulting table will be called A.
SELECT
id,
SUBSTRING_INDEX( 'name' , ' ', 1 ) AS a,
SUBSTRING_INDEX(SUBSTRING_INDEX( 'name' , ' ', 2 ),' ',-1) AS b
FROM ms_absen
This is pseudo (i haven't tested it) code that shows the idea.
select e.id_emp, e.name, a.id
from ms_employee as e, A as a
where e.name like concat('%',left(a.part1,3),'%')
or e.name like concat('%',left(a.part2,3),'%')

Adding another value below the row

Hey guys i have did some coding in mysql to add a new line value to a row..
SELECT
babe
FROM
(SELECT
concat_ws(' ', 'assword \n') AS babe,
) test;
When i did like this i get an output like
BABE
assword name
What i need is an output like
BABE
assword
name(this would be below assword)
Is there any mysql functions to do this ??...or can i UPDATE the row ??..
I am a newbie in mysql. Hope you guys can help me out..Thanks in advance..
The statement includes a newline character in the babe column. You can confirm this by using the HEX() function to view the character encodings.
For example:
SELECT HEX(t.babe)
FROM ( SELECT CONCAT_WS(' ', 'assword \n') AS babe ) t
On my system, that Will output:
617373776F7264200A
It's easy enough to understand what was returned
a s s w o r d \n
61 73 73 77 6F 72 64 20 0A
(In the original query, there's an extraneous comma that will prevent the statement from running. Perhaps there was another expression in the SELECT list of the inline view, and that was returning the 'name' value that's shown in the example output. But we don't see any reference to that in the outer query.
It's not clear why you need the newline character. If you want to return:
BABE
-----------
asssword
name
That looks like two separate rows to me. But it's valid (but peculiar) to do this:
SELECT t.babe
FROM ( SELECT CONCAT_WS(' ', 'assword \nname') AS babe ) t
FOLLOWUP
Q: i just wanted to know how to add a new row below the assword ..if u know please edit the answer
It's not clear what result you are trying to achieve. The specification, divorced from the context of a use-case, is just bizarre.
A: If I had a need to return two rows: one row with the literal 'assword' and another row "below" it with the literal 'name', I could do this:
( SELECT 'assword' AS some_string )
UNION ALL
( SELECT 'name' AS some_string )
ORDER BY some_string
In this particular case, we can get the ordering we need by a simple reference to the column in the ORDER BY clause.
In the more general case, when there isn't a convenient expression for the ORDER BY clause, I would add an additional column, and perform a SELECT on the resultset from the UNION ALL operation. In this example, that "extra" column is named seq:
SELECT t.some_string
FROM ( SELECT 'assword' AS some_string, 1 AS seq
UNION ALL SELECT 'name', 2
)
ORDER BY t.seq
As another example:
( SELECT 'do' AS tone, 1 AS seq )
UNION ALL ( SELECT 're', 2 )
UNION ALL ( SELECT 'mi', 3 )
UNION ALL ( SELECT 'fa', 4 )
ORDER BY seq
I'd only need to add an outer SELECT if I needed a projection operation (for example, to remove the seq column from the returned resultset.
SELECT t.tone
FROM ( SELECT 'do' AS tone, 1 AS seq
UNION ALL SELECT 're', 2
UNION ALL SELECT 'mi', 3
UNION ALL SELECT 'fa', 4
)
ORDER BY t.seq

Select multiple sums with MySQL query and display them in separate columns

Let's say I have a hypothetical table like so that records when some player in some game scores a point:
name points
------------
bob 10
mike 03
mike 04
bob 06
How would I get the sum of each player's scores and display them side by side in one query?
Total Points Table
bob mike
16 07
My (pseudo)-query is:
SELECT sum(points) as "Bob" WHERE name="bob",
sum(points) as "Mike" WHERE name="mike"
FROM score_table
You can pivot your data 'manually':
SELECT SUM(CASE WHEN name='bob' THEN points END) as bob,
SUM(CASE WHEN name='mike' THEN points END) as mike
FROM score_table
but this will not work if the list of your players is dynamic.
In pure sql:
SELECT
sum( (name = 'bob') * points) as Bob,
sum( (name = 'mike') * points) as Mike,
-- etc
FROM score_table;
This neat solution works because of mysql's booleans evaluating as 1 for true and 0 for false, allowing you to multiply truth of a test with a numeric column. I've used it lots of times for "pivots" and I like the brevity.
Are the player names all known up front? If so, you can do:
SELECT SUM(CASE WHEN name = 'bob' THEN points ELSE 0 END) AS bob,
SUM(CASE WHEN name = 'mike' THEN points ELSE 0 END) AS mike,
... so on for each player ...
FROM score_table
If you don't, you still might be able to use the same method, but you'd probably have to build the query dynamically. Basically, you'd SELECT DISTINCT name ..., then use that result set to build each of the CASE statements, then execute the result SQL.
This is called pivoting the table:
SELECT SUM(IF(name = "Bob", points, 0)) AS points_bob,
SUM(IF(name = "Mike", points, 0)) AS points_mike
FROM score_table
SELECT sum(points), name
FROM `table`
GROUP BY name
Or for the pivot
SELECT sum(if(name = 'mike',points,0)),
sum(if(name = 'bob',points,0))
FROM `table
you can use pivot function also for the same thing .. even by performance vise it is better option to use pivot for pivoting... (i am talking about oracle database)..
you can use following query for this as well..
-- (if you have only these two column in you table then it will be good to see output else for other additional column you will get null values)
select * from game_scores
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));
in this query you will get data very fast and you have to add or remove player name only one place
:)
if you have more then these two column in your table then you can use following query
WITH pivot_data AS (
SELECT points,name
FROM game_scores
)
SELECT *
FROM pivot_data
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));