How use money format in pivot in SQL Server - sql-server

I am using this code. It returns the sum() of price and shows it with delimiter like money format
SELECT
REPLACE(CONVERT(VARCHAR(20), CAST( sum(unitprice) AS MONEY), 1), '.00', '')
FROM
tchargecard_factor
GROUP BY
datetimeentry
and it works fine.
Please tell me how can I get this result from pivot table?
My code is :
'SELECT *, (' + #GrandTotalCol + ') AS [Grand Total]
INTO #temp_MatchesTotal
FROM
(SELECT
idpoint, [last mendub name], pointsalename,
agentname, mobile, remain, typegroupname
FROM
zomorod_webapp_temp.dbo.chargecard_sum_typegroup4) A
PIVOT
(SUM(remain)
FOR typegroupname IN (' +#columnHeaders + ')) B
ORDER BY
idpoint
When I use this code, it is not allowing me to use cast or convert type in sum(remain). I get this error:
Msg 195, Level 15, State 1, Line 9
'REPLACE' is not a recognized aggregate function
How can I fix it?

Related

Incorrect syntax near the keyword 'SELECT' using IN clause

I am having trouble with my query, i am trying to do a pivot table using data from SQL and I want to sum up figures from a table for all years past from 2000.
This is my query
SELECT
*
FROM
(SELECT
Vendor_code, Vendor_name, Ord_date, SubTot,
DateRecieved, CurrencyCode, YearReceived
FROM
[BL_CUSTOM PO HISTORY SUMMARY]) AS S
PIVOT
(SUM(S.SubTot)
FOR s.YearRecived IN (SELECT STUFF((SELECT ', ' + cast(year as VARCHAR(10)) FROM [BL_CUSTOM YEAR COUNT] FOR XML PATH('')),1,1,'')) ) as pvt
I am getting the following error:
Msg 156, Level 15, State 1, Line 33
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 33
Incorrect syntax near ')'.
Refer to the syntax in https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
I believe your query,
SELECT STUFF((SELECT ', ' + cast(year as VARCHAR(10)) FROM [BL_CUSTOM YEAR COUNT] FOR XML PATH('')),1,1,''))
is causing the problem.

SQL Server Regular expression extract pattern from DB colomn

I have a question about SQL Server: I have a database column with a pattern which is like this:
up to 10 digits
then a comma
up to 10 digits
then a semicolon
e.g.
100000161, 100000031; 100000243, 100000021;
100000161, 100000031; 100000243, 100000021;
and I want to extract within the pattern the first digits (up to 10) (1.) and then a semicolon (4.)
(or, in other words, remove everything from the semicolon to the next semicolon)
100000161; 100000243; 100000161; 100000243;
Can you please advice me how to establish this in SQL Server? Im not very familiar with regex and therefore have no clue how to fix this.
Thanks,
Alex
Try this
Declare #Sql Table (SqlCol nvarchar(max))
INSERT INTO #Sql
SELECT'100000161,100000031;100000243,100000021;100000161,100000031;100000243,100000021;'
;WITH cte
AS (SELECT Row_number()
OVER(
ORDER BY (SELECT NULL)) AS Rno,
split.a.value('.', 'VARCHAR(1000)') AS Data
FROM (SELECT Cast('<S>'
+ Replace( Replace(sqlcol, ';', ','), ',',
'</S><S>')
+ '</S>'AS XML) AS Data
FROM #Sql)AS A
CROSS apply data.nodes('/S') AS Split(a))
SELECT Stuff((SELECT '; ' + data
FROM cte
WHERE rno%2 <> 0
AND data <> ''
FOR xml path ('')), 1, 2, '') AS ExpectedData
ExpectedData
-------------
100000161; 100000243; 100000161; 100000243
I believe this will get you what you are after as long as that pattern truly holds. If not it's fairly easy to ensure it does conform to that pattern and then apply this
Select Substring(TargetCol, 1, 10) + ';' From TargetTable
You can take advantage of SQL Server's XML support to convert the input string into an XML value and query it with XQuery and XPath expressions.
For example, the following query will replace each ; with </b><a> and each , to </a><b> to turn each string into <a>100000161</a><a>100000243</a><a />. After that, you can select individual <a> nodes with /a[1], /a[2] :
declare #table table (it nvarchar(200))
insert into #table values
('100000161, 100000031; 100000243, 100000021;'),
('100000161, 100000031; 100000243, 100000021;')
select
xCol.value('/a[1]','nvarchar(200)'),
xCol.value('/a[2]','nvarchar(200)')
from (
select convert(xml, '<a>'
+ replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','')
+ '</a>')
.query('a') as xCol
from #table) as tmp
-------------------------
A1 A2
100000161 100000243
100000161 100000243
value extracts a single value from an XML field. nodes returns a table of nodes that match the XPath expression. The following query will return all "keys" :
select
a.value('.','nvarchar(200)')
from (
select convert(xml, '<a>'
+ replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','')
+ '</a>')
.query('a') as xCol
from #table) as tmp
cross apply xCol.nodes('a') as y(a)
where a.value('.','nvarchar(200)')<>''
------------
100000161
100000243
100000161
100000243
With 200K rows of data though, I'd seriously consider transforming the data when loading it and storing it in indivisual, indexable columns, or add a separate, related table. Applying string manipulation functions on a column means that the server can't use any covering indexes to speed up queries.
If that's not possible (why?) I'd consider at least adding a separate XML-typed column that would contain the same data in XML form, to allow the creation of an XML index.

SQL Query datetime issue

I have a query on SQL Server that's finding wrong results based on a datetime condition.
SET LANGUAGE Português
select distinct
CONVERT(varchar(10), DATENAME(MONTH, i9_parcelaBase.i9_data_vencimento)) + '/' + CONVERT(varchar(10),
DATENAME(YEAR,i9_parcelaBase.i9_data_vencimento)) AS Periodo,
i9_parcelaBase.i9_data_vencimento,
i9_parcelaBase.i9_data_limite_envio_nf,
i9_parcelaBase.i9_status_atual,
i9_processo_statusBase.i9_status,
i9_processo_statusBase.i9_name
--i9_nota_fiscalBase.i9_nota_fiscalid as ID
from i9_parcelaBase
left join i9_processo_statusBase
on i9_parcelaBase.i9_status_atual = i9_processo_statusBase.i9_processo_statusId
where i9_processo_statusBase.i9_entidade = 100000002
and i9_parcelaBase.i9_data_vencimento between CONVERT(varchar(10), year(getdate())-1) + '-' + CONVERT(varchar(10), month(getdate())+1) + '-1'
and CONVERT(varchar(10), year(getdate())) + '-' + CONVERT(varchar(10), month(getdate())) + '-1'
order by i9_data_vencimento asc
Basically, Month that's receiving data without '0' before (when necessary).
Sample:
Actual return: '2017-6-1'
Expected return '2017-06-01'
Can anyone help me to solve this problem?
By the look of your query, i9_data_vencimento is expected to end with just -1, not -01. You can cast the string into a date, then recast it back as a string as a way to format it:
select distinct
CONVERT(varchar(10), DATENAME(MONTH, i9_parcelaBase.i9_data_vencimento)) + '/' + CONVERT(varchar(10),
DATENAME(YEAR,i9_parcelaBase.i9_data_vencimento)) AS Periodo,
CONVERT( VARCHAR(10), CONVERT( DATETIME, i9_parcelaBase.i9_data_vencimento ), 120 ) AS i9_data_vencimento,
:
:
Also, considering that i9_data_vencimento is just a string, and assuming it always ends with '1' in the format 'yyyy-mm-1', you could use a LEFT function to strip off the last character and replace it with '01':
SELECT DISTINCT
:
LEFT(i9_parcelaBase.i9_data_vencimento, 8) + '01' AS i9_data_vencimento,
:

SQL Server 2012 pivot error

I'm doing a dynamic pivot to create a cross tab with dates. The #Query generated is :-
SELECT [R_Ref]
,CONCAT(datepart(yyyy,[Transaction_Date]), '-', RIGHT('00' + CONVERT(NVARCHAR(2), datepart(M,[Transaction_Date])), 2)) as 'Month'
,[Transaction_Value]
FROM [T-Files].[dbo].[T_Transactions]
as MyTX
PIVOT (
SUM(MyTX.[Transaction_Value])
FOR MyTX.[Month] IN ( [2016-05], [2016-06], [2016-07])
) p
but this generates these errors
Msg 207, Level 16, State 1, Line 9
Invalid column name 'Month'.
Msg 207, Level 16, State 1, Line 3
Invalid column name 'Transaction_Value'.
I can run the top select without the pivot fine, what's wrong in the PIVOT statement?
TIA :o)
You need to put pivot source in sub-select since you are making some manipulation to generate Month.
SELECT *
FROM (SELECT [R_Ref],
Concat(Datepart(yyyy, [Transaction_Date]), '-', RIGHT('00'+ CONVERT(NVARCHAR(2), Datepart(M, [Transaction_Date])), 2)) AS 'Month',
MyTX.[Transaction_Value]
FROM [T-Files].[dbo].[T_Transactions] AS MyTX) A
PIVOT ( Sum([Transaction_Value])
FOR [Month] IN ( [2016-05],
[2016-06],
[2016-07]) ) p

Concatenate the result of an ordered String_Split in a variable

In a SqlServer database I use, the database name is something like StackExchange.Audio.Meta, or StackExchange.Audio or StackOverflow . By sheer luck this is also the url for a website. I only need split it on the dots and reverse it: meta.audio.stackexchange. Adding http:// and .com and I'm done. Obviously Stackoverflow doesn't need any reversing.
Using the SqlServer 2016 string_split function I can easy split and reorder its result:
select value
from string_split(db_name(),'.')
order by row_number() over( order by (select 1)) desc
This gives me
| Value |
-----------------
| Meta |
| Audio |
| StackExchange |
As I need to have the url in a variable I hoped to concatenate it using this answer so my attempt looks like this:
declare #revname nvarchar(150)
select #revname = coalesce(#revname +'.','') + value
from string_split(db_name(),'.')
order by row_number() over( order by (select 1)) desc
However this only returns me the last value, StackExchange. I already noticed the warnings on that answer that this trick only works for certain execution plans as explained here.
The problem seems to be caused by the order by clause. Without that I get all values, but then in the wrong order. I tried to a add ltrimand rtrim function as suggested in the Microsoft article as well as a subquery but so far without luck.
Is there a way I can nudge the Sql Server 2016 Query Engine to concatenate the ordered result from that string_split in a variable?
I do know I can use for XML or even a plain cursor to get the result I need but I don't want to give up this elegant solution yet.
As I'm running this on the Stack Exchange Data Explorer I can't use functions, as we lack the permission to create those. I can do Stored procedures but I hoped I could evade those.
I prepared a SEDE Query to experiment with. The database names to expect are either without dots, aka StackOverflow, with 1 dot: StackOverflow.Meta or 2 dots, `StackExchange.Audio.Meta, the full list of databases is here
I think you are over-complicating things. You could use PARSENAME:
SELECT 'http://' + PARSENAME(db_name(),1) +
ISNULL('.' + PARSENAME(db_name(),2),'') + ISNULL('.'+PARSENAME(db_name(),3),'')
+ '.com'
This is exactly why I have the Presentation Sequence (PS) in my split function. People often scoff at using a UDF for such items, but it is generally a one-time hit to parse something for later consumption.
Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.')
Returns
Key_PS Key_Value
1 meta
2 audio
3 stackexchange
The UDF
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('meta.audio.stackexchange','.')
-- Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
-- Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')
Returns #ReturnTable Table (Key_PS int IDENTITY(1,1) NOT NULL , Key_Value varchar(max))
As
Begin
Declare #intPos int,#SubStr varchar(max)
Set #IntPos = CharIndex(#delimeter, #String)
Set #String = Replace(#String,#delimeter+#delimeter,#delimeter)
While #IntPos > 0
Begin
Set #SubStr = Substring(#String, 0, #IntPos)
Insert into #ReturnTable (Key_Value) values (#SubStr)
Set #String = Replace(#String, #SubStr + #delimeter, '')
Set #IntPos = CharIndex(#delimeter, #String)
End
Insert into #ReturnTable (Key_Value) values (#String)
Return
End
Probably less elegant solution but it takes only a few lines and works with any number of dots.
;with cte as (--build xml
select 1 num, cast('<str><s>'+replace(db_name(),'.','</s><s>')+'</s></str>' as xml) str
)
,x as (--make table from xml
select row_number() over(order by num) rn, --add numbers to sort later
t.v.value('.[1]','varchar(50)') s
from cte cross apply cte.str.nodes('str/s') t(v)
)
--combine into string
select STUFF((SELECT '.' + s AS [text()]
FROM x
order by rn desc --in reverse order
FOR XML PATH('')
), 1, 1, '' ) name
Is there a way I can nudge the Sql Server 2016 Query Engine to concatenate the ordered result from that string_split in a variable?
You can just use CONCAT:
DECLARE #URL NVARCHAR(MAX)
SELECT #URL = CONCAT(value, '.', #URL) FROM STRING_SPLIT(DB_NAME(), '.')
SET #URL = CONCAT('http://', LOWER(#URL), 'com');
The reversal is accomplished by the order of parameters to CONCAT. Here's an example.
It changes StackExchange.Garage.Meta to http://meta.garage.stackexchange.com.
This can be used to split and reverse strings in general, but note that it does leave a trailing delimiter. I'm sure you could add some logic or a COALESCE in there to make that not happen.
Also note that vNext will be adding STRING_AGG.
To answer the 'X' of this XY problem, and to address the HTTPS switch (especially for Meta sites) and some other site name changes, I've written the following SEDE query which outputs all site names in the format used on the network site list.
SELECT name,
LOWER('https://' +
IIF(PATINDEX('%.Mathoverflow%', name) > 0,
IIF(PATINDEX('%.Meta', name) > 0, 'meta.mathoverflow.net', 'mathoverflow.net'),
IIF(PATINDEX('%.Ubuntu%', name) > 0,
IIF(PATINDEX('%.Meta', name) > 0, 'meta.askubuntu.com', 'askubuntu.com'),
IIF(PATINDEX('StackExchange.%', name) > 0,
CASE SUBSTRING(name, 15, 200)
WHEN 'Audio' THEN 'video'
WHEN 'Audio.Meta' THEN 'video.meta'
WHEN 'Beer' THEN 'alcohol'
WHEN 'Beer.Meta' THEN 'alcohol.meta'
WHEN 'CogSci' THEN 'psychology'
WHEN 'CogSci.Meta' THEN 'psychology.meta'
WHEN 'Garage' THEN 'mechanics'
WHEN 'Garage.Meta' THEN 'mechanics.meta'
WHEN 'Health' THEN 'medicalsciences'
WHEN 'Health.Meta' THEN 'medicalsciences.meta'
WHEN 'Moderators' THEN 'communitybuilding'
WHEN 'Moderators.Meta' THEN 'communitybuilding.meta'
WHEN 'Photography' THEN 'photo'
WHEN 'Photography.Meta' THEN 'photo.meta'
WHEN 'Programmers' THEN 'softwareengineering'
WHEN 'Programmers.Meta' THEN 'softwareengineering.meta'
WHEN 'Vegetarian' THEN 'vegetarianism'
WHEN 'Vegetarian.Meta' THEN 'vegetarianism.meta'
WHEN 'Writers' THEN 'writing'
WHEN 'Writers.Meta' THEN 'writing.meta'
ELSE SUBSTRING(name, 15, 200)
END + '.stackexchange.com',
IIF(PATINDEX('StackOverflow.%', name) > 0,
CASE SUBSTRING(name, 15, 200)
WHEN 'Br' THEN 'pt'
WHEN 'Br.Meta' THEN 'pt.meta'
ELSE SUBSTRING(name, 15, 200)
END + '.stackoverflow.com',
IIF(PATINDEX('%.Meta', name) > 0,
'meta.' + SUBSTRING(name, 0, PATINDEX('%.Meta', name)) + '.com',
name + '.com'
)
)
)
)
) + '/'
)
FROM sys.databases WHERE database_id > 5

Resources