SQL 2008 VS 2012 Error: Incorrect syntax near the keyword 'COMPUTE' - sql

My friend sent me the commands that he wrote in server 2008 and they worked with no problems, mine however from a copy and past did not work with 2012. Is there any reason why? Here is the code:
Use Kudler_Database
SELECT AccountNumber, [Description], ShortDescription,Balance
FROM Chart_of_Accounts
ORDER BY left (AccountNumber, 2)
COMPUTE SUM(Balance) BY left (AccountNumber, 2)
COMPUTE SUM(Balance);
Here is the error :
Msg 156, Level 15, State 1, Line 6 Incorrect syntax near the keyword
'COMPUTE'.

COMPUTE is no longer available in SQL server 2012, thats why you are getting that error. See this page:
Discontinued Database Engine Functionality in SQL Server 2012
It said that:
This topic describes the Database Engine features that are no longer
available in SQL Server 2012:
*Transact-SQL syntax | COMPUTE / COMPUTE BY *

A kind of hack with RollUp since Compute By is deprecated in SQL Server 2012 - (see "SQL SERVER – Use ROLL UP Clause instead of COMPUTE BY")
DECLARE #t TABLE(AccountNumber VARCHAR(10),[Description] VARCHAR(100),ShortDescription VARCHAR(100),Balance INT)
INSERT INTO #t SELECT '1234567890','Some Description for 1st Account','Short Description for 1st Account',2000 Union All
SELECT '2345678901','Some Description for 2nd Account','Short Description for 2nd Account',3000 Union All
SELECT '1234567890','Some Description for 1st Account','Short Description for 1st Account',4000
SELECT
AccountNumber
,Balance
,Total = SUM(Balance)
FROM #t
GROUP BY AccountNumber,Balance
WITH ROLLUP
Result
AccountNumber Balance total
1234567890 2000 2000
1234567890 4000 4000
1234567890 NULL 6000
2345678901 3000 3000
2345678901 NULL 3000
NULL NULL 9000
OR
you can use the below
DECLARE #t TABLE(AccountNumber VARCHAR(10),[Description] VARCHAR(100),ShortDescription VARCHAR(100),Balance INT)
INSERT INTO #t SELECT '1234567890','Some Description for 1st Account','Short Description for 1st Account',2000 Union All
SELECT '2345678901','Some Description for 2nd Account','Short Description for 2nd Account',3000 Union All
SELECT '1234567890','Some Description for 1st Account','Short Description for 1st Account',4000
;With CTE AS
(
SELECT
AccountNumber
,[Description]
,ShortDescription
,Balance
,SubTotal = SUM(Balance) OVER (PARTITION BY AccountNumber ORDER BY LEFT (AccountNumber, 2))
,Rn = ROW_NUMBER() OVER(PARTITION BY AccountNumber ORDER BY LEFT (AccountNumber, 2))
FROM #t)
SELECT
AccountNumber
,[Description]
,ShortDescription
,Balance = CAST(Balance AS VARCHAR(10))
,SubTotal = CASE WHEN Rn != 1 THEN NULL ELSE SubTotal END
FROM CTE
UNION ALL
SELECT
' ', ' ',' ' ,'Total Amount' , SUM(Balance) FROM CTE
The output being
AccountNumber Description ShortDescription Balance SubTotal
1234567890 Some Description for 1st Account Short Description for 1st Account 2000 6000
1234567890 Some Description for 1st Account Short Description for 1st Account 4000 NULL
2345678901 Some Description for 2nd Account Short Description for 2nd Account 3000 3000
Total Amount 9000

You can create something similar with GROUPING SETS but it all comes in one resultset, eg something like:
SELECT AcGroup, AccountNumber, [Description], ShortDescription, SUM( Balance ) Balance, GROUPING_ID(AcGroup, AccountNumber)
FROM ( SELECT LEFT( AccountNumber, 2 ) AcGroup, * FROM Chart_of_Accounts ) x
GROUP BY GROUPING SETS( (AcGroup), ( AccountNumber, [Description], ShortDescription ), () )
SELECT AcGroup, SUM( Balance ) Balance
FROM ( SELECT LEFT( AccountNumber, 2 ) AcGroup, * FROM Chart_of_Accounts ) x
GROUP BY GROUPING SETS( AcGroup, () )
SELECT AcGroup, SUM( Balance ) Balance
FROM ( SELECT LEFT( AccountNumber, 2 ) AcGroup, * FROM Chart_of_Accounts ) x
GROUP BY AcGroup WITH CUBE
I've added GROUPING_ID() which makes it easier to work out if the source is an original, summary to total row.
I always wondered how you would consume something like that as the multiple resultsets make it difficult to handle. You can't pass it to another stored procedure, you can't copy it paste it directly to Excel (without messing around), passing to a .net client would be awkward. How did you consume the previous code?
HTH

Related

SQL Pivot and Distinct from new Columns

I have a table called ADMIN that originally looks like this
KEY VALUE
Version1 2019_RQK#2019
Version2 2019_RQK#2020
Version2 2019_RQK#2021
Version2 2019_RQK#2022
Version2 2020_TKA#2020
Version2 2020_TKA#2021
Version2 2020_TKA#2022
Version2 2020_TKA#2023
And I am try to change it to look like this
VERSION YEAR1 YEAR2 YEAR3 YEAR4
2019_RQK 2019 2020 2021 2022
2020_TKA 2020 2021 2022 2023
I wrote some SQL in order to get the left and right versions of the [VALUE] columns but I dont know how to condense it so that it only shows a DISTINCT as for the left side of the [VALUE] column. I tried to use distinct but it still brings up the same repeated entries, this is what I've written so far, I dont know if PIVOT function would work here I tried a few things it didn't end up correct.
SELECT DISTINCT LEFT([VALUE], 7) AS VERSION, RIGHT([VALUE], 4) AS YEAR
FROM ADMIN
WHERE [KEY] LIKE '%VERSION%'
Just gives me, not sure how to change it in the same query
VERSION YEAR
2019_RQK 2019
2019_RQK 2020
2019_RQK 2021
2019_RQK 2022
2020_TKA 2020
2020_TKA 2021
2020_TKA 2022
2020_TKA 2023
So, yes, you need a PIVOT table to do that. You can learn all about them here, which has a pretty straightforward (and quick!) walkthrough to understand why it works magic.
To PIVOT this table, we need to add a column for YEAR1, YEAR2, etc.. so they can be our headers/new columns. I'll do that with a basic ROW_NUMBER function. I know this example has 4 maximum new columns per entry, so I'm hardcoding them in, but the link above explains how you can dynamically generate the IN statement if you have an unknown number of maximum columns.
Please note, my test table was created with col1 and col2 because I am lazy. You should swap those for the actual column names.
SELECT * FROM (
-- we start with your basic table, as you provided
SELECT
LEFT(col2, 7) AS VERSION,
RIGHT(col2, 4) AS YEAR,
ROW_NUMBER() OVER (partition by LEFT(col2, 7) order by RIGHT(col2, 4)) as YearNum /* sort these by the proper year, so we don't get of order */
FROM ADMIN
WHERE col1 LIKE '%VERSION%'
) versionResults
PIVOT (
max([YEAR]) -- grab the year
for [YearNum] -- this column holds our new column headers
in ( /* these are the possible YearNum values, now our new column headers */
[1],
[2],
[3],
[4]
)
) as pivotResults
Demo here.
You need to also extract the first 4 chars as the "base year", then subtract the "Year" from the "Base Year" (and add 1) to get an integer value (1-4) and use those as the PIVOT list.
Example Fiddle
The reason this is "difficult" is that you have 3 key values stored in 1 column. At least it's fixed width so easy enough to break apart consistently.
If the VALUE column contains differently formatted data, this won't work.
CREATE TABLE Admin
( Key1 char(8)
, Val char(13)
);
INSERT INTO Admin (Key1, Val)
VALUES
('Version1','2019_RQK#2019')
, ('Version2','2019_RQK#2020')
, ('Version2','2019_RQK#2021')
, ('Version2','2019_RQK#2022')
, ('Version2','2020_TKA#2020')
, ('Version2','2020_TKA#2021')
, ('Version2','2020_TKA#2022')
, ('Version2','2020_TKA#2023');
WITH Src AS (
SELECT
Version = SUBSTRING(Val,1,8)
, Year = CAST(SUBSTRING(Val,10,4) as int)
, YearCt = CAST(SUBSTRING(Val,10,4) as int) - CAST(SUBSTRING(Val,1,4) as int) + 1
FROM Admin
)
SELECT
pvt.Version
, Year1 = pvt.[1]
, Year2 = pvt.[2]
, Year3 = pvt.[3]
, Year4 = pvt.[4]
FROM Src
PIVOT (MAX(Year) FOR YearCt IN ([1],[2],[3],[4])) pvt;
Using dynamical pivoting such as below one would be a better option in terms of picking the currently inserted years with no applying any manipulation to the query while the data change
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SET #cols = ( SELECT STRING_AGG(CONCAT('[year',[n],']'),',')
FROM (SELECT DISTINCT
ROW_NUMBER() OVER
(PARTITION BY LEFT([value], 7) ORDER BY [value]) AS [n]
FROM [admin] ) q );
SET #query =
N'SELECT *
FROM
(
SELECT DISTINCT LEFT([value], 7) AS version, RIGHT([value], 4) AS year,
CONCAT(''year'',ROW_NUMBER() OVER
(PARTITION BY LEFT([value], 7)
ORDER BY RIGHT([value], 4))) AS [n]
FROM [admin]
WHERE [key] LIKE ''%VERSION%'' ) q
PIVOT (
MAX([year]) FOR [n] IN (' + #cols + N')
) p
ORDER BY [version]';
EXEC sp_executesql #query;
Demo
Btw, you might also split the value by # sign SUBSTRING([value],1,CHARINDEX('#',[value])-1) in order to extract version, and SUBSTRING([value],CHARINDEX('#',[value])+1,LEN([value])) in order to extract year columns without specifying the length values as arguments within the functions as an alternative.

sql lowest running balance in a group

I've been trying for days to solve this problem to no solution.
I want to get the lowest running balance in a group.
Here is a sample data
The running balance is imaginary and is not part of the table.
the running balance is also computed dynamically.
the problem is I want to get the lowest running balance in a Specific month (January)
so the output should be 150 for memberid 10001 and 175 for memberid 10002 as highlighted in the image.
my desired out put should be
memberid | balance
10001 | 150
10002 | 175
Is that possible using sql query only?
PS. Using c# to compute lowest running balance is very slow since I have more than 600,000 records in my table.
I've updated the question.
The answer provided by Mihir Shah gave me the idea how solve my problem.
His answer takes to much time to process making it as slow as my computation on my c# program because his code loops on every record.
Here is my answer to get the minimum lowest value in a specific group (specific month) with a running value or running total without sacrificing a lot of performance.
with IniMonth1 as
(
select a.memberid, a.iniDeposit, a.iniWithdrawal,
(cast(a.iniDeposit as decimal(10,2)) - cast(a.iniWithdrawal as decimal(10,2))) as RunningTotal
from
(
select b.memberid, sum(b.depositamt) as iniDeposit, sum(b.withdrawalamt) as iniWithdrawal
from savings b
where trdate < '01/01/2016'
group by b.memberid
) a /*gets all the memberid, sum of deposit amount and withdrawal amt from the beginning of the savings before the specific month */
where cast(a.iniDeposit as decimal(10,2)) - cast(a.iniWithdrawal as decimal(10,2)) > 0 /*filters zero savings */
)
,DetailMonth1 as
(
select a.memberid, a.depositamt,a.withdrawalamt,
(cast(a.depositamt as decimal(10,2)) - cast(a.withdrawalamt as decimal(10,2))) as totalBal,
Row_Number() Over(Partition By a.memberid Order By a.trdate Asc) RowID
from savings a
where
a.trdate >= '01/01/2016'
and
a.trdate <= '01/31/2016'
and (a.depositamt<>0 or a.withdrawalamt<>0)
) /* gets all record within the specific month and gives a no of row as an id for the running value in the next procedure*/
,ComputedDetailMonth1 as
(
select a.memberid, min(a.runningbalance) as MinRunningBal
from
(
select a.rowid, a.memberid, a.totalbal,
(
sum(b.totalbal) +
(case
when c.runningtotal is null then 0
else c.runningtotal
end)
)as runningbalance , c.runningtotal as oldbalance
from DetailMonth1 a
inner join DetailMonth1 b
on b.rowid<=a.rowid
and a.memberid=b.memberid
left join IniMonth1 c
on a.memberid=c.memberid
group by a.rowid,a.memberid,a.totalbal,c.runningtotal
) a
group by a.memberid
) /* the loop is only for the records of the specific month only making it much faster */
/* this gets the running balance of specific month ONLY and ADD the sum total of IniMonth1 using join to get the running balance from the beginning of savings to the specific month */
/* I then get the minimum of the output using the min function*/
, OldBalanceWithNoNewSavingsMonth1 as
(
select a.memberid,a.RunningTotal
from
IniMonth1 a
left join
DetailMonth1 b
on a.memberid = b.memberid
where b.totalbal is null
)/*this gets all the savings that is not zero and has no transaction in the specific month making and this will become the default value as the lowest value if the member has no transaction in the specific month. */
,finalComputedMonth1 as
(
select a.memberid,a.runningTotal as MinRunTotal from OldBalanceWithNoNewSavingsMonth1 a
union
select b.memberid,b.MinRunningBal from ComputedDetailMonth1 b
)/*the record with minimum running total with clients that has a transaction in the specific month Unions with the members with no current transaction in the specific month*/
select * from finalComputedMonth1 order by memberid /* display the final output */
I have more than 600k savings record on my savings table
Surprisingly the performance of this code is very efficient.
It takes almost 2hr using my c# program to manually compute every record of all the members.
This code makes only 2 secs and at most 9 secs just to compute everything.
i Just display to c# for another 2secs.
The output of this code was tested and compared with my computation using my c# program.
May be below one is help you
Set Nocount On;
Declare #CashFlow Table
(
savingsid Varchar(50)
,memberid Int
,trdate Date
,deposit Decimal(18,2)
,withdrawal Decimal(18,2)
)
Insert Into #CashFlow(savingsid,memberid,trdate,deposit,withdrawal) Values
('10001-0002',10001,'01/01/2015',1000,0)
,('10001-0003',10001,'01/07/2015',25,0)
,('10001-0004',10001,'01/13/2015',25,0)
,('10001-0005',10001,'01/19/2015',0,900)
,('10001-0006',10001,'01/25/2015',25,0)
,('10001-0007',10001,'01/31/2015',25,0)
,('10001-0008',10001,'02/06/2015',25,0)
,('10001-0009',10001,'02/12/2015',25,0)
,('10001-0010',10001,'02/18/2015',0,200)
,('10002-0001',10002,'01/01/2015',500,0)
,('10002-0002',10002,'01/07/2015',25,0)
,('10002-0003',10002,'01/13/2015',0,200)
,('10002-0004',10002,'01/19/2015',25,0)
,('10002-0005',10002,'01/25/2015',25,0)
,('10002-0006',10002,'01/31/2015',0,200)
,('10002-0007',10002,'02/06/2015',25,0)
,('10002-0008',10002,'02/12/2015',25,0)
,('10002-0009',10002,'02/12/2015',0,200)
;With TrialBalance As
(
Select Row_Number() Over(Partition By cf.memberid Order By cf.trdate Asc) RowNum
,cf.memberid
,cf.deposit
,cf.withdrawal
,cf.trdate
From #CashFlow As cf
)
,RunningBalance As
(
Select tb.RowNum
,tb.memberid
,tb.deposit
,tb.withdrawal
,tb.trdate
From TrialBalance As tb
Where tb.RowNum = 1
Union All
Select tb.RowNum
,rb.memberid
,Cast((rb.deposit + tb.deposit - tb.withdrawal) As Decimal(18,2))
,rb.withdrawal
,tb.trdate
From TrialBalance As tb
Join RunningBalance As rb On tb.RowNum = (rb.Rownum + 1) And tb.memberid = rb.memberid
)
Select rb.memberid
,Min(rb.deposit) As runningBalance
From RunningBalance As rb
Where Year(rb.trdate) = 2015
And Month(rb.trdate) = 1
Group By rb.memberid

Sort string as number in sql server

I have a column that contains data like this. dashes indicate multi copies of the same invoice and these have to be sorted in ascending order
790711
790109-1
790109-11
790109-2
i have to sort it in increasing order by this number but since this is a varchar field it sorts in alphabetical order like this
790109-1
790109-11
790109-2
790711
in order to fix this i tried replacing the -(dash) with empty and then casting it as a number and then sorting on that
select cast(replace(invoiceid,'-','') as decimal) as invoiceSort...............order by invoiceSort asc
while this is better and sorts like this
invoiceSort
790711 (790711) <-----this is wrong now as it should come later than 790109
790109-1 (7901091)
790109-2 (7901092)
790109-11 (79010911)
Someone suggested to me to split invoice id on the - (dash ) and order by on the 2 split parts
like=====> order by split1 asc,split2 asc (790109,1)
which would work i think but how would i split the column.
The various split functions on the internet are those that return a table while in this case i would be requiring a scalar function.
Are there any other approaches that can be used? The data is shown in grid view and grid view doesn't support sorting on 2 columns by default ( i can implement it though :) ) so if any simpler approaches are there i would be very nice.
EDIT : thanks for all the answers. While every answer is correct i have chosen the answer which allowed me to incorporate these columns in the GridView Sorting with minimum re factoring of the sql queries.
Judicious use of REVERSE, CHARINDEX, and SUBSTRING, can get us what we want. I have used hopefully-explanatory columns names in my code below to illustrate what's going on.
Set up sample data:
DECLARE #Invoice TABLE (
InvoiceNumber nvarchar(10)
);
INSERT #Invoice VALUES
('790711')
,('790709-1')
,('790709-11')
,('790709-21')
,('790709-212')
,('790709-2')
SELECT * FROM #Invoice
Sample data:
InvoiceNumber
-------------
790711
790709-1
790709-11
790709-21
790709-212
790709-2
And here's the code. I have a nagging feeling the final expressions could be simplified.
SELECT
InvoiceNumber
,REVERSE(InvoiceNumber)
AS Reversed
,CHARINDEX('-',REVERSE(InvoiceNumber))
AS HyphenIndexWithinReversed
,SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))
AS ReversedWithoutAffix
,SUBSTRING(InvoiceNumber,1+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixIncludingHyphen
,SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixExcludingHyphen
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
AS AffixAsInt
,REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
AS WithoutAffix
FROM #Invoice
ORDER BY
-- WithoutAffix
REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
-- AffixAsInt
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
Output:
InvoiceNumber Reversed HyphenIndexWithinReversed ReversedWithoutAffix AffixIncludingHyphen AffixExcludingHyphen AffixAsInt WithoutAffix
------------- ---------- ------------------------- -------------------- -------------------- -------------------- ----------- ------------
790709-1 1-907097 2 907097 -1 1 1 790709
790709-2 2-907097 2 907097 -2 2 2 790709
790709-11 11-907097 3 907097 -11 11 11 790709
790709-21 12-907097 3 907097 -21 21 21 790709
790709-212 212-907097 4 907097 -212 212 212 790709
790711 117097 0 117097 0 790711
Note that all you actually need is the ORDER BY clause, the rest is just to show my working, which goes like this:
Reverse the string, find the hyphen, get the substring after the hyphen, reverse that part: This is the number without any affix
The length of (the number without any affix) tells us how many characters to drop from the start in order to get the affix including the hyphen. Drop an additional character to get just the numeric part, and convert this to int. Fortunately we get a break from SQL Server in that this conversion gives zero for an empty string.
Finally, having got these two pieces, we simple ORDER BY (the number without any affix) and then by (the numeric value of the affix). This is the final order we seek.
The code would be more concise if SQL Server allowed us to say SUBSTRING(value, start) to get the string starting at that point, but it doesn't, so we have to say SUBSTRING(value, start, LEN(value)) a lot.
Try this one -
Query:
DECLARE #Invoice TABLE (InvoiceNumber VARCHAR(10))
INSERT #Invoice
VALUES
('790711')
, ('790709-1')
, ('790709-21')
, ('790709-11')
, ('790709-211')
, ('790709-2')
;WITH cte AS
(
SELECT
InvoiceNumber
, lenght = LEN(InvoiceNumber)
, delimeter = CHARINDEX('-', InvoiceNumber)
FROM #Invoice
)
SELECT InvoiceNumber
FROM cte
CROSS JOIN (
SELECT repl = MAX(lenght - delimeter)
FROM cte
WHERE delimeter != 0
) mx
ORDER BY
SUBSTRING(InvoiceNumber, 1, ISNULL(NULLIF(delimeter - 1, -1), lenght))
, RIGHT(REPLICATE('0', repl) + SUBSTRING(InvoiceNumber, delimeter + 1, lenght), repl)
Output:
InvoiceNumber
-------------
790709-1
790709-2
790709-11
790709-21
790709-211
790711
Try this
SELECT invoiceid FROM Invoice
ORDER BY
CASE WHEN PatIndex('%[-]%',invoiceid) > 0
THEN LEFT(invoiceid,PatIndex('%[-]%',invoiceid)-1)
ELSE invoiceid END * 1
,CASE WHEN PatIndex('%[-]%',REVERSE(invoiceid)) > 0
THEN RIGHT(invoiceid,PatIndex('%[-]%',REVERSE(invoiceid))-1)
ELSE NULL END * 1
SQLFiddle Demo
Above query uses two case statements
Sorts first part of Invoiceid 790109-1 (eg: 790709)
Sorts second part of Invoiceid after splitting with '-' 790109-1 (eg: 1)
For detailed understanding check the below SQLfiddle
SQLFiddle Detailed Demo
OR use 'CHARINDEX'
SELECT invoiceid FROM Invoice
ORDER BY
CASE WHEN CHARINDEX('-', invoiceid) > 0
THEN LEFT(invoiceid, CHARINDEX('-', invoiceid)-1)
ELSE invoiceid END * 1
,CASE WHEN CHARINDEX('-', REVERSE(invoiceid)) > 0
THEN RIGHT(invoiceid, CHARINDEX('-', REVERSE(invoiceid))-1)
ELSE NULL END * 1
Order by each part separately is the simplest and reliable way to go, why look for other approaches? Take a look at this simple query.
select *
from Invoice
order by Convert(int, SUBSTRING(invoiceid, 0, CHARINDEX('-',invoiceid+'-'))) asc,
Convert(int, SUBSTRING(invoiceid, CHARINDEX('-',invoiceid)+1, LEN(invoiceid)-CHARINDEX('-',invoiceid))) asc
Plenty of good answers here, but I think this one might be the most compact order by clause that is effective:
SELECT *
FROM Invoice
ORDER BY LEFT(InvoiceId,CHARINDEX('-',InvoiceId+'-'))
,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC
Demo: - SQL Fiddle
Note, I added the '790709' version to my test, since some of the methods listed here aren't treating the no-suffix version as lesser than the with-suffix versions.
If your invoiceID varies in length, before the '-' that is, then you'd need:
SELECT *
FROM Invoice
ORDER BY CAST(LEFT(list,CHARINDEX('-',list+'-')-1)AS INT)
,CAST(RIGHT(InvoiceId,CHARINDEX('-',REVERSE(InvoiceId)+'-'))AS INT)DESC
Demo with varying lengths before the dash: SQL Fiddle
My version:
declare #Len int
select #Len = (select max (len (invoiceid) - charindex ( '-', invoiceid))-1 from MyTable)
select
invoiceid ,
cast (SUBSTRING (invoiceid ,1,charindex ( '-', invoiceid )-1) as int) * POWER (10,#Len) +
cast (right(invoiceid, len (invoiceid) - charindex ( '-', invoiceid) ) as int )
from MyTable
You can implement this as a new column to your table:
ALTER TABLE MyTable ADD COLUMN invoice_numeric_id int null
GO
declare #Len int
select #Len = (select max (len (invoiceid) - charindex ( '-', invoiceid))-1 from MyTable)
UPDATE TABLE MyTable
SET invoice_numeric_id = cast (SUBSTRING (invoiceid ,1,charindex ( '-', invoiceid )-1) as int) * POWER (10,#Len) +
cast (right(invoiceid, len (invoiceid) - charindex ( '-', invoiceid) ) as int )
One way is to split InvoiceId into its parts, and then sort on the parts. Here I use a derived table, but it could be done with a CTE or a temporary table as well.
select InvoiceId, InvoiceId1, InvoiceId2
from
(
select
InvoiceId,
substring(InvoiceId, 0, charindex('-', InvoiceId, 0)) as InvoiceId1,
substring(InvoiceId, charindex('-', InvoiceId, 0)+1, len(InvoiceId)) as InvoiceId2
FROM Invoice
) tmp
order by
cast((case when len(InvoiceId1) > 0 then InvoiceId1 else InvoiceId2 end) as int),
cast((case when len(InvoiceId1) > 0 then InvoiceId2 else '0' end) as int)
In the above, InvoiceId1 and InvoiceId2 are the component parts of InvoiceId. The outer select includes the parts, but only for demonstration purposes - you do not need to do this in your select.
The derived table (the inner select) grabs the InvoiceId as well as the component parts. The way it works is this:
When there is a dash in InvoiceId, InvoiceId1 will contain the first part of the number and InvoiceId2 will contain the second.
When there is not a dash, InvoiceId1 will be empty and InvoiceId2 will contain the entire number.
The second case above (no dash) is not optimal because ideally InvoiceId1 would contain the number and InvoiceId2 would be empty. To make the inner select work optimally would decrease the readability of the select. I chose the non-optimal, more readable, approach since it is good enough to allow for sorting.
This is why the ORDER BY clause tests for the length - it needs to handle the two cases above.
Demo at SQL Fiddle
Break the sort into two sections:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE TestData
(
data varchar(20)
)
INSERT TestData
SELECT '790711' as data
UNION
SELECT '790109-1'
UNION
SELECT '790109-11'
UNION
SELECT '790109-2'
Query 1:
SELECT *
FROM TestData
ORDER BY
FLOOR(CAST(REPLACE(data, '-', '.') AS FLOAT)),
CASE WHEN CHARINDEX('-', data) > 0
THEN CAST(RIGHT(data, len(data) - CHARINDEX('-', data)) AS INT)
ELSE 0
END
Results:
| DATA |
-------------
| 790109-1 |
| 790109-2 |
| 790109-11 |
| 790711 |
Try:
select invoiceid ... order by Convert(decimal(18, 2), REPLACE(invoiceid, '-', '.'))

Problem on Pivot table in SQL server

create table newtest (
Section varchar(50),
Department varchar(50),
salesamount float
)
Insert into newtest
select 'Sec1','IT',2000.89 union
select 'Sec1','IT',1000.89 union
select 'Sec1','IT',3000.89 union
select 'Sec1','BPO',2000.89 union
select 'Sec2','BPO',5000.89 union
select 'Sec2','IT',2700.89 union
select 'Sec2','BPO',2000.89 union
select 'Sec3','IT',6000.89 union
select 'Sec3','IT',2000.89 union
select 'Sec3','BPO',9000.89 union
select 'Sec4','IT',2000.89 union
select 'Sec4','BPO',6000.89 union
select 'Sec3','BPO',1000.89 union
select 'Sec4','IT',3000.89
select * from newtest
Select section, department, SUM(salesamount)
from newtest
Group by Section, Department
--use of pivot
select [Sec1] AS Sec1BPO,
[Sec2] AS Sec2BPO,
[Sec3] AS Sec3BPO,
[Sec4] AS Sec4BPO,
[Sec1] AS Sec1IT,
[Sec2] AS Sec2IT,
[Sec3] AS Sec3IT,
[Sec4] AS Sec4IT
from (select Section, Department, salesamount
from newtest) as Sourcetable
PIVOT( SUM([salesamount])
FOR [Section] IN ([Sec1],[Sec2],[Sec3],[Sec4]) ) AS Pivottable
ORDER BY Department
Please help me to resolve the issue....I got the result when execute above code as
Sec1BPO Sec2BPO Sec3BPO Sec4BPO Sec1IT Sec2IT Sec3IT Sec4IT
-------------------------------------------------------------------------
2000.89 7001.78 10001.78 6000.89 2000.89 7001.78 10001.78 6000.89
6002.67 2700.89 8001.78 5001.78 6002.67 2700.89 8001.78 5001.78
but I need as
Sec1BPO Sec2BPO Sec3BPO Sec4BPO Sec1IT Sec2IT Sec3IT Sec4IT
-----------------------------------------------------------------------
2000.89 7001.78 10001.78 6000.89 6002.67 2700.89 8001.78 5001.78
Please Help me to get desired result.
You could try something like this:
select Sec1BPO,
Sec2BPO,
Sec3BPO,
Sec4BPO,
Sec1IT,
Sec2IT,
Sec3IT,
Sec4IT
from (select Section + Department AS SectDept, salesamount
from newtest) as Sourcetable
PIVOT( SUM([salesamount])
FOR SectDept IN (Sec1BPO, Sec2BPO, Sec3BPO, Sec4BPO,
Sec1IT, Sec2IT, Sec3IT, Sec4IT) ) AS Pivottable
ORDER BY 1
UPDATE
Just one word of caution – the above solution, when applied in general, might put you at risk of summing together pieces of data that were not meant to be done so. That is, taking your present example, if it contained rows with both Sec1, BPO and Sec1B, PO as combinations of Section and Department, both combinations would end up concatenated as Sec1BPO and thus added up together, which would obviously be wrong.
Therefore, some delimiter should probably be used when concatenating the parts to exclude such duplicates, like space or a different character that is known for sure to be absent from the values to be concatenated. I mean something like this:
select [Sec1 BPO],
[Sec2 BPO],
[Sec3 BPO],
[Sec4 BPO],
[Sec1 IT],
[Sec2 IT],
[Sec3 IT],
[Sec4 IT]
from (select Section + ' ' + Department AS SectDept, salesamount
from newtest) as Sourcetable
PIVOT( SUM([salesamount])
FOR SectDept IN ([Sec1 BPO], [Sec2 BPO], [Sec3 BPO], [Sec4 BPO],
[Sec1 IT], [Sec2 IT], [Sec3 IT], [Sec4 IT])
) AS Pivottable
ORDER BY 1
(Thanks #Conrad Frix for raising the issue.)
;WITH CTE AS (
select
Department,
[Sec1] ,
[Sec2] ,
[Sec3] ,
[Sec4]
from (select Section, Department, salesamount
from #newtest) as Sourcetable
PIVOT( SUM([salesamount])
FOR [Section] IN ([Sec1],[Sec2],[Sec3],[Sec4]) ) AS Pivottable
)
SELECT
a.sec1 Sec1bpo, a.sec2 sec2bpo, a.sec3 sec3bpo, a.sec4 sec4bpo,
b.sec1 Sec1it, b.sec2 sec2it, b.sec3 sec3it, b.sec4 sec4it
FROM
cte a, cte b
WHERE
a.department = 'BPO' and B.department = 'it'​
to see it working go to the Data.SE query SO Question 6881168
Note I used a Table variable instead of a table because Create table doesn't work on Data.SE
Output
Sec1bpo sec2bpo sec3bpo sec4bpo Sec1it sec2it sec3it sec4it
------- ------- -------- ------- ------- ------- ------- -------
2000.89 7001.78 10001.78 6000.89 6002.67 2700.89 8001.78 5001.78

SQL query ...multiple max value selection. Help needed

Business World 1256987 monthly 10 2009-10-28
Business World 1256987 monthly 10 2009-09-23
Business World 1256987 monthly 10 2009-08-18
Linux 4 U 456734 monthly 25 2009-12-24
Linux 4 U 456734 monthly 25 2009-11-11
Linux 4 U 456734 monthly 25 2009-10-28
I get this result with the query:
SELECT DISTINCT ljm.journelname,ljm. subscription_id,
ljm.frequency,ljm.publisher, ljm.price, ljd.receipt_date
FROM lib_journals_master ljm,
lib_subscriptionhistory
lsh,lib_journal_details ljd
WHERE ljd.journal_id=ljm.id
ORDER BY ljm.publisher
What I need is the latest date in each journal?
I tried this query:
SELECT DISTINCT ljm.journelname, ljm.subscription_id,
ljm.frequency, ljm.publisher, ljm.price,ljd.receipt_date
FROM lib_journals_master ljm,
lib_subscriptionhistory lsh,
lib_journal_details ljd
WHERE ljd.journal_id=ljm.id
AND ljd.receipt_date = (
SELECT max(ljd.receipt_date)
from lib_journal_details ljd)
But it gives me the maximum from the entire column. My needed result will have two dates (maximum of each magazine), but this query gives me only one?
You could change the WHERE statement to look up the last date for each journal:
AND ljd.receipt_date = (
SELECT max(subljd.receipt_date)
from lib_journal_details subljd
where subljd.journelname = ljd.journelname)
Make sure to give the table in the subquery a different alias from the table in the main query.
You should use Group By if you need the Max from date.
Should look something like this:
SELECT
ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
, **MAX(ljd.receipt_date)**
FROM
lib_journals_master ljm
, lib_subscriptionhistory lsh
, lib_journal_details ljd
WHERE
ljd.journal_id=ljm.id
GROUP BY
ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
Something like this should work for you.
SELECT ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
,md.max_receipt_date
FROM lib_journals_master ljm
, ( SELECT journal_id
, max(receipt_date) as max_receipt_date
FROM lib_journal_details
GROUP BY journal_id) md
WHERE ljm.id = md.journal_id
/
Note that I have removed the tables from the FROM clause which don't contribute anything to the query. You may need to replace them if yopu simplified your scenario for our benefit.
Separate this into two queries one will get journal name and latest date
declare table #table (journalName as varchar,saleDate as datetime)
insert into #table
select journalName,max(saleDate) from JournalTable group by journalName
select all fields you need from your table and join #table with them. join on journalName.
Sounds like top of group. You can use a CTE in SQL Server:
;WITH journeldata AS
(
SELECT
ljm.journelname
,ljm.subscription_id
,ljm.frequency
,ljm.publisher
,ljm.price
,ljd.receipt_date
,ROW_NUMBER() OVER (PARTITION BY ljm.journelname ORDER BY ljd.receipt_date DESC) AS RowNumber
FROM
lib_journals_master ljm
,lib_subscriptionhistory lsh
,lib_journal_details ljd
WHERE
ljd.journal_id=ljm.id
AND ljm.subscription_id = ljm.subscription_id
)
SELECT
journelname
,subscription_id
,frequency
,publisher
,price
,receipt_date
FROM journeldata
WHERE RowNumber = 1