SQL Server Fill Month Gaps in Groups - sql-server

I have a table for example like below:
declare #test table(Aid int, Bid int, CheckMonth date, Avalue decimal(18,2))
insert into #test (Aid, Bid, CheckMonth, Avalue)
values (1, 4, '2014-07-05', 123.00)
,(1, 4, '2014-08-01', 467.00)
,(1, 4, '2014-11-03', 876.00)
,(1, 4, '2014-12-01', 876.00)
,(2, 6, '2016-01-02', 23.00)
,(2, 6, '2016-03-14', 56.00)
,(2, 6, '2016-04-17', 98.00)
,(2, 6, '2016-07-01', 90.00)
I wish to fill the gaps in months (in CheckMonth column above) with 0.00 values (in Avalue column).
Data is grouped by Aid and Bid columns.
The result should look like below:
Aid Bid CheckMonth Avalue
1 4 '2014-07-05' 123.00
1 4 '2014-08-01' 467.00
1 4 '2014-09-01' 0.00 -->inserted
1 4 '2014-10-01' 0.00 -->inserted
1 4 '2014-11-03' 876.00
1 4 '2014-12-01' 876.00
2 6 '2016-01-02' 23.00
2 6 '2016-02-01' 0.00 -->inserted
2 6 '2016-03-14' 56.00
2 6 '2016-04-17' 98.00
2 6 '2016-05-01' 0.00 -->inserted
2 6 '2016-06-01' 0.00 -->inserted
2 6 '2016-07-01' 90.00
Any help is appreciated.
Thanks.

One option uses a recursive query to generate the month starts for each (aid, bid) tuple; you can then left join the generated resultset with the original table:
with cte as (
select
aid,
bid,
datefromparts(year(min(checkMonth)), month(min(checkMonth)), 1) dt,
datefromparts(year(max(checkMonth)), month(max(checkMonth)), 1) maxDt
from #test
group by aid, bid
union all
select
aid,
bid,
dateadd(month, 1, dt),
maxDt
from cte
where dt < maxDt
)
select c.aid, c.bid, coalesce(t.checkMonth, c.dt) checkMonth, coalesce(t.avalue, 0) avalue
from cte c
left join #test t
on t.aid = c.aid
and t.bid = c.bid
and t.checkMonth >= c.dt
and t.checkMonth < dateadd(month, 1, c.dt)
order by c.aid, c.bid, c.dt
Demo on DB Fiddle:
aid | bid | checkMonth | avalue
--: | --: | :--------- | :-----
1 | 4 | 2014-07-05 | 123.00
1 | 4 | 2014-08-01 | 467.00
1 | 4 | 2014-09-01 | 0.00
1 | 4 | 2014-10-01 | 0.00
1 | 4 | 2014-11-03 | 876.00
1 | 4 | 2014-12-01 | 876.00
2 | 6 | 2016-01-02 | 23.00
2 | 6 | 2016-02-01 | 0.00
2 | 6 | 2016-03-14 | 56.00
2 | 6 | 2016-04-17 | 98.00
2 | 6 | 2016-05-01 | 0.00
2 | 6 | 2016-06-01 | 0.00
2 | 6 | 2016-07-01 | 90.00

Related

CASE WHEN to calculate tax on a tier based tax system

I have a table with user incomes and i wish to calculate their income tax percentage based on that income. The issue is that the tax rate is different for each bracket e.g.:
MinLimit| MaxLimit| TaxRate
0 | 14000 | 10.50
14001 | 48000 | 17.50
48001 | 70000 | 30.00
70001 | 1000000 | 33.00
So if the income of 1 person is 49,000 then they would be taxed as follows:
14000 * 0.1050 = 1470
34000 * 0.1750 = 5950 (34,000 is income between 14k -48k)
1000 * 0.30 = 300 (1000 is remaining income)
total = 1470 + 5950 + 300 = 7720
I am running on SQL Server 2017 Express. I have tried running a chained CASE-WHEN statement i.e.
CASE WHEN
THEN
WHEN
THEN
and so on...
but I can figure out how to add the logic of subtracting the remaining amount. Please find my code below.
SELECT 'emp_name' AS 'Director',
SUM(ABS([Transaction Amount])) AS 'INCOME',
CASE WHEN (SUM(ABS([Transaction Amount])) < 14000)
THEN ((SUM(ABS([Transaction Amount])) - 14000) * 0.1050)
WHEN (SUM(ABS([Transaction Amount])) > 14000 and (SUM(ABS([Transaction Amount])) < 48001))
THEN (((SUM(ABS([Transaction Amount])) - 14000) * 0.1050) - 48000) * 0.1750 end AS 'Income Tax'
FROM Transactions
EDIT 1:
Input Data:
Transaction Type| PAYEE | Transaction Amount
DEBIT | DEBIT | -184.00
CREDIT | CREDIT | 4000.00
...
Output Data:
Director | INCOME | Income Tax
emp_name | 45100.00| NULL
Please let me know where I am going wrong or if my thinking is incorrect.
A correlated subquery may be the simplest to read and understand:
declare #t table (MinLimitExclusive int, MaxLimitInclusive int, TaxRate decimal(5,2))
insert into #t(MinLimitExclusive,MaxLimitInclusive,TaxRate) values
(0 ,14000 , 10.50),
(14000,48000 , 17.50),
(48000,70000 , 30.00),
(70000,1000000, 33.00)
declare #transactions table (Income decimal(10,2))
insert into #transactions (Income) values (49000)
select
(Income - MinLimitExclusive) * TaxRate / 100 +
(select SUM((rates2.MaxLimitInclusive - rates2.MinLimitExclusive) * rates2.TaxRate / 100)
from #t rates2 where rates2.MaxLimitInclusive <= rates.MinLimitExclusive)
from
#transactions tr
inner join
#t rates
on
tr.Income > rates.MinLimitExclusive and tr.Income <= rates.MaxLimitInclusive
It's remarkably simplified when you realise that the only maths you need to do related to the actual income is related to the bracket it actually fits in - all of the lower rate brackets, by implication, were used in their entirety so you can compute those other taxes purely from the rates table.
I've changed your rates data slightly to make the computations straightforward and not need lots of +/-1 adjustments.
I suggest that you start with a MinLimit of 1 instead of 0. The rest of the calculation is straight forward:
declare #taxslabs table (minlimit int, maxlimit int, taxrate decimal(18, 2));
insert into #taxslabs values
(1, 14000, 10.50),
(14001, 48000, 17.50),
(48001, 70000, 30.00),
(70001, 1000000, 33.00);
select persons.*, taxslabs.*, taxableamount, taxableamount * taxrate / 100 as taxamount
from (values
(1, 49000),
(2, 70000),
(3, 70001)
) as persons(id, income)
cross join #taxslabs as taxslabs
cross apply (select case when income <= maxlimit then income else maxlimit end - minlimit + 1) as ca(taxableamount)
where minlimit <= income
You can place this query inside a subquery and use GROUP BY ... SUM() or SUM() OVER (PARTITION BY) to calculate the sum of taxes.
Sample output:
| id | income | minlimit | maxlimit | taxrate | taxableamount | taxamount |
|----|--------|----------|----------|---------|---------------|------------------|
| 1 | 49000 | 1 | 14000 | 10.50 | 14000 | 1470.000000 |
| 1 | 49000 | 14001 | 48000 | 17.50 | 34000 | 5950.000000 |
| 1 | 49000 | 48001 | 70000 | 30.00 | 1000 | 300.000000 |
| 2 | 70000 | 1 | 14000 | 10.50 | 14000 | 1470.000000 |
| 2 | 70000 | 14001 | 48000 | 17.50 | 34000 | 5950.000000 |
| 2 | 70000 | 48001 | 70000 | 30.00 | 22000 | 6600.000000 |
| 3 | 70001 | 1 | 14000 | 10.50 | 14000 | 1470.000000 |
| 3 | 70001 | 14001 | 48000 | 17.50 | 34000 | 5950.000000 |
| 3 | 70001 | 48001 | 70000 | 30.00 | 22000 | 6600.000000 |
| 3 | 70001 | 70001 | 1000000 | 33.00 | 1 | 0.330000 |
i think this relevant query using group by on transaction table and join to rate taxe table can be down excepted result :
CREATE TABLE #Transaction
(
tID int PRIMARY KEY,
tIdUser varchar(50),
Amount decimal(9,3)
);
CREATE TABLE #RefTaxe
(
pID int PRIMARY KEY,
minLimit int,
maxLImit int,
rate decimal(9,3)
);
INSERT INTO #Transaction
SELECT 1, 'User1', 1259.3
UNION
SELECT 2, 'User1', 10259.3
UNION
SELECT 3, 'User3', 30581.3
UNION
SELECT 4, 'User2', 75000.36
UNION
SELECT 5, 'User2', 15000.36
UNION
SELECT 6, 'User4', 45000.36
UNION
SELECT 7, 'User4', 5000.36
INSERT INTO #RefTaxe
select 1,0,14000,10.50
UNION
SELECT 2,14001,48000,17.50
UNION
SELECT 3,48001,70000,30.00
UNION
SELECT 4,70001,1000000,33.00
-- SELECT * FROM #Transaction
-- SELECT * FROM #RefTaxe
-- SELECT tIdUser,SUM(AMOUNT) as SumAmount, CAST(FLOOR(SUM(AMOUNT))as int) as SumAsInt FROM #Transaction GROUP BY tIdUser
/***/
-- Perform select
/***/
SELECT tIdUser, SumAmount as 'DetaxedAmount' ,SumAmount * (rate/100) as TaxOfAmount, SumAmount+ SumAmount * (rate/100) as TaxedAmount
FROM #RefTaxe RT
JOIN (
SELECT tIdUser,SUM(AMOUNT) as SumAmount, CAST(FLOOR(SUM(AMOUNT))as int) as SumAsInt
FROM #Transaction GROUP BY tIdUser
) AS GroupedTR ON RT.minLimit <= SumAsInt AND RT.maxLImit >= SumAsInt
/***/
DROP TABLE #Transaction
DROP TABLE #RefTaxe
Result output :
tIdUser DetaxedAmount TaxOfAmount TaxedAmount
User1 11518.600 1209.453000 12728.053
User2 90000.720 29700.237600 119700.958
User3 30581.300 5351.727500 35933.028
User4 50000.720 15000.216000 65000.936
This Query is calculating very exact results against tax rules define by Pakistan Government.[Thanks & Regards - Noman Ali].
Select
Salary,
Salary*12 as YearlySalary,
case
when salary * 12 Between 600001 and 1200000 then ((salary * 12 - 600000) / 100 * 2.5) / 12
when salary * 12 Between 1200001 and 2400000 then (15000 + (salary * 12 - 1200000) / 100 * 12.50) / 12
when salary * 12 Between 2400001 and 3600000 then (165000 + (salary * 12 - 2400000) / 100 * 20.0) / 12
when salary * 12 Between 3600001 and 6000000 then (405000 + (salary * 12 - 3600000) / 100 * 25.0 ) / 12
when salary * 12 Between 6000001 and 12000000 then (1005000 + (salary* 12 - 6000000) / 100 * 32.5 ) / 12
when salary * 12 > 12000001 then (2955000 + (salary * 12 - 12000000) / 100 * 35.0 ) / 12
else 0 end as IncomeTax
from Employees

TSQL: Find Groups of Records in a Sequence of Records

Sorry for the title if you find it incorrect, I really wasn't sure how to name this question. There is probably a term for this type of query/pattern.
I have a sequence of records that need to be ordered by date, the records have a condition I would like to "group" by (SomeCondition) to get the earliest start date and latest end date (taking NULL's into account) but I'm unsure how to accomplish the query (if it's even possible). The original records in the table look something like;
-----------------------------------------------------------
| AbcID | XyzID | StartDate | EndDate | SomeCondition |
-----------------------------------------------------------
| 1 | 1 | 2018-01-01 | 2018-03-05 | 1 |
| 2 | 1 | 2018-04-20 | 2018-05-01 | 1 |
| 3 | 1 | 2018-05-02 | 2018-05-15 | 0 |
| 4 | 1 | 2018-06-01 | 2018-07-01 | 1 |
| 5 | 1 | 2018-08-01 | NULL | 1 |
| 6 | 2 | 2018-01-01 | 2018-06-30 | 1 |
| 7 | 2 | 2018-07-01 | 2018-08-31 | 0 |
-----------------------------------------------------------
The result I'm going for would be;
-----------------------------------
| XyzID | StartDate | EndDate |
-----------------------------------
| 1 | 2018-01-01 | 2018-05-01 |
| 1 | 2018-06-01 | NULL |
| 2 | 2018-01-01 | 2018-06-30 |
-----------------------------------
Thanks for any help/insight, even if it's "not possible".
Solving this problem requires you to solve it piece by piece. Here are the steps that I used to do that:
Determine when the island begins (when SomeCondition is false)
Create an "ID" number for each island (within each XyzID) by summing the number of IslandBegins while considering the records in AbcID order
Determine the first and last AbcID within each XyzID/IslandNumber combination where SomeCondition is true
Use the previous step as a guide as to what StartDate / EndDate you should get for each record in the result set
Sample Data:
declare #sample_data table
(
AbcID int
, XyzID int
, StartDate date
, EndDate date
, SomeCondition bit
)
insert into #sample_data
values (1, 1, '2018-01-01', '2018-03-05', 1)
, (2, 1, '2018-04-20', '2018-05-01', 1)
, (3, 1, '2018-05-02', '2018-05-15', 0)
, (4, 1, '2018-06-01', '2018-07-01', 1)
, (5, 1, '2018-08-01', NULL, 1)
, (6, 2, '2018-01-01', '2018-06-30', 1)
, (7, 2, '2018-07-01', '2018-08-31', 0)
Answer:
The comments in the code show which step each part of the CTE is accomplishing.
with island_bgn as
(
--Step 1
select d.AbcID
, d.XyzID
, d.StartDate
, d.EndDate
, d.SomeCondition
, case when d.SomeCondition = 0 then 1 else 0 end as IslandBegin
from #sample_data as d
)
, island_nbr as
(
--Step 2
select b.AbcID
, b.XyzID
, b.StartDate
, b.EndDate
, b.SomeCondition
, b.IslandBegin
, sum(b.IslandBegin) over (partition by b.XyzID order by b.AbcID asc) as IslandNumber
from island_bgn as b
)
, prelim as
(
--Step 3
select n.XyzID
, n.IslandNumber
, min(n.AbcID) as AbcIDMin
, max(n.AbcID) as AbcIDMax
from island_nbr as n
where 1=1
and n.SomeCondition = 1
group by n.XyzID
, n.IslandNumber
)
--Step 4
select p.XyzID
, a.StartDate
, b.EndDate
from prelim as p
inner join #sample_data as a on p.AbcIDMin = a.AbcID
inner join #sample_data as b on p.AbcIDMax = b.AbcID
order by p.XyzID
, a.StartDate
, b.EndDate
Results:
+-------+------------+------------+
| XyzID | StartDate | EndDate |
+-------+------------+------------+
| 1 | 2018-01-01 | 2018-05-01 |
+-------+------------+------------+
| 1 | 2018-06-01 | NULL |
+-------+------------+------------+
| 2 | 2018-01-01 | 2018-06-30 |
+-------+------------+------------+

How can i get the days between results dates for each seperate pat_id?

I'm looking to get the days between result dates for each patient: only looking at result dates where the result value is <90.00
;WITH patient_results AS (
SELECT * FROM (VALUES
(1, 'EA11AEE3-1D90-4602-9A37-0000007E2293', '85.10' ,'2015-12-11'),
(1, '27BCD3E4-2381-4139-B420-0000025B4113', '91.50' ,'2016-01-05'),
(1, 'D8969360-45D6-487B-AF94-0000035F78B0', '81.00' ,'2016-07-21'),
(5, '446E6413-442A-452A-BCF4-000006AA9896', '58.00' ,'2014-07-01'),
(5, '00305129-BC14-4A12-8368-00000AC04A9B', '53.00' ,'2014-12-13'),
(5, '96A67E53-2D6C-430B-A01F-00000AE4C37B', '42.80' ,'2015-02-01'),
(5, '7C330511-3E99-488C-AF5E-00000BDFA3FF', '54.00' ,'2015-07-01'),
(8, '62A2806A-4969-417A-B4DF-D547621CC594', '89.00' ,'2016-03-10'),
(8, '3B9F4E5B-3433-4F21-850A-FC2127A24B72', '92.60' ,'2016-06-30'),
(8, '1A2D780D-8C11-451C-8A64-6D49140B6232', '88.00' ,'2016-08-05')
) as t (pat_id, visit_id, result_value, result_date))
Based on the above looking to get something like this:
PAT_ID | VISIT_ID | RESULT_VALUE | RESULT_DATE| DAYSBETWEENRESULTDATES
1 | EA11AEE3-1D90-4602-9A37-0000007E2293 | 85.10 | 2015-12-11 | 0
1 | D8969360-45D6-487B-AF94-0000035F78B0 | 81.00 | 2016-07-21 | 223
5 | 446E6413-442A-452A-BCF4-000006AA9896 | 58.00 | 2014-07-01 | 0
5 | 00305129-BC14-4A12-8368-00000AC04A9B | 53.00 | 2014-12-13 | 165
5 | 96A67E53-2D6C-430B-A01F-00000AE4C37B | 42.80 | 2015-02-01 | 50
5 | 7C330511-3E99-488C-AF5E-00000BDFA3FF | 54.00 | 2015-07-01 | 150
8 | 62A2806A-4969-417A-B4DF-D547621CC594 | 89.00 | 2016-03-10 | 0
8 | 1A2D780D-8C11-451C-8A64-6D49140B6232 | 84.00 | 2016-08-05 | 148
I am using Sql Server 2012, Sql server management studio version 11.0.5058.0
Thank you.
Try this.
;WITH patient_results
AS
(
SELECT * FROM
(VALUES (1, 'EA11AEE3-1D90-4602-9A37-0000007E2293', '85.10' ,'2015-12-11'),
(1, '27BCD3E4-2381-4139-B420-0000025B4113', '91.50' ,'2016-01-05'),
(1, 'D8969360-45D6-487B-AF94-0000035F78B0', '81.00' ,'2016-07-21'),
(5, '446E6413-442A-452A-BCF4-000006AA9896', '58.00' ,'2014-07-01'),
(5, '00305129-BC14-4A12-8368-00000AC04A9B', '53.00' ,'2014-12-13'),
(5, '96A67E53-2D6C-430B-A01F-00000AE4C37B', '42.80' ,'2015-02-01'),
(5, '7C330511-3E99-488C-AF5E-00000BDFA3FF', '54.00' ,'2015-07-01'),
(8, '62A2806A-4969-417A-B4DF-D547621CC594', '89.00' ,'2016-03-10'),
(8, '3B9F4E5B-3433-4F21-850A-FC2127A24B72', '92.60' ,'2016-06-30'),
(8, '1A2D780D-8C11-451C-8A64-6D49140B6232', '88.00' ,'2016-08-05') )
as t (pat_id, visit_id, result_value, result_date))
SELECT *, ISNULL(DATEDIFF(DAY, LAG(result_date) OVER(PARTITION BY pat_id ORDER BY result_date), result_date), 0) as daysBetweenResultDates
FROM patient_results
WHERE result_value < 90.00
Result
pat_id visit_id result_value result_date DaysBetweenResultDates
1 EA11AEE3-1D90-4602-9A37-0000007E2293 85.10 2015-12-11 0
1 D8969360-45D6-487B-AF94-0000035F78B0 81.00 2016-07-21 223
5 446E6413-442A-452A-BCF4-000006AA9896 58.00 2014-07-01 0
5 00305129-BC14-4A12-8368-00000AC04A9B 53.00 2014-12-13 165
5 96A67E53-2D6C-430B-A01F-00000AE4C37B 42.80 2015-02-01 50
5 7C330511-3E99-488C-AF5E-00000BDFA3FF 54.00 2015-07-01 150
8 62A2806A-4969-417A-B4DF-D547621CC594 89.00 2016-03-10 0
8 1A2D780D-8C11-451C-8A64-6D49140B6232 88.00 2016-08-05 148
You can use OUTER APPLY to get previous values:
SELECT p.*,
ISNULL(DATEDIFF(DAY,t.result_date,p.result_date),0) AS DaysBetweenResultDates
FROM patient_results p
OUTER APPLY (
SELECT TOP 1 result_date
FROM patient_results
WHERE pat_id = p.pat_id and
result_date < p.result_date and
result_value < 90
ORDER BY result_date DESC) as t
WHERE p.result_value <90

Sorting table in sql server

My table data like
id LedgerName
1 "105 AAA"
2 "102 sss"
3 "GGGG"
4 "107 BBB"
5 "BBBB"
6 "101 TTT"
i want sorting the Ledger like
6 "101 TTT"
2 "102 sss"
1 "105 AAA"
4 "107 BBB"
5 "BBBB"
3 "GGGG"
Normal Order by is not working.
i used split function to split for number based sorting in order by ..
how to fix this issue
With the data you have provided a regular order by on LedgerName is doing what you want.
Below is version that deals with data that is a bit more complicated.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table YourTable
(
id int,
LedgerName varchar(20)
)
insert into YourTable values
(1, '105 AAA' ),
(2, '1020 sss' ),
(3, ' ' ),
(4, null ),
(5, '0' ),
(6, '999 sss' ),
(7, '9999 sss' ),
(8, 'GGGG' ),
(9, '107 BBB' ),
(10, 'BBBB' ),
(11, '101 TTT' )
Query 1:
select id,
LedgerName
from YourTable
order by case when patindex('%[^0-9]%', isnull(LedgerName, '')+' ') = 1 then 1 else 0 end,
cast(left(LedgerName, patindex('%[^0-9]%', LedgerName+' ')-1) as int),
LedgerName
Results:
| ID | LEDGERNAME |
-------------------
| 5 | 0 |
| 11 | 101 TTT |
| 1 | 105 AAA |
| 9 | 107 BBB |
| 6 | 999 sss |
| 2 | 1020 sss |
| 7 | 9999 sss |
| 4 | (null) |
| 3 | |
| 10 | BBBB |
| 8 | GGGG |

How to merge rows to one row in SQL Server

I have a table like this:
- ID | CurrencyID | LendID | Price
- 3 | 1 | 1 | 1.2
- 3 | 1 | 2 | 1.3
- 3 | 1 | 3 | 1.4
- 3 | 2 | 1 | 1.5
- 3 | 2 | 2 | 1.6
- 3 | 2 | 3 | 1.7
- 4 | 2 | 3 | 2.0
There are totally 4 currencies 1,2,3,4
There are totally 3 lend 1,2,3
I want to get a result like below:
ID | CurrencyIDLendID_11_Price | CIDID_12_Price | CIDLID_13_Price | CIDLID_21_Price | CIDLID_22_Price | CIDLID_23_Price | CIDLID_31_Price | CIDLID_32_Price | CIDLID_33_Price | CIDLID_41_Price | CIDLID_42_Price | CIDLID_43_Price
3 | 1.2 | 1.3 | 1.4 | 1.5 | 1.6 | 1.7 | 0 | 0 | 0 | 0 | 0 | 0
4 | 0 | 0 | 0 | 0 | 0 | 2.0 | 0 | 0 | 0 | 0 | 0 | 0
I know it is now good description, but what I want to do is to merge many records to one record.
This is called pivoting and one of the ways how to do the pivoting is to use grouping with conditional aggregating:
WITH cidlid AS (
SELECT
ID,
CurrencyIDLendID = CurrencyID * 10 + LendID,
Price
FROM atable
)
SELECT
ID,
CurrencyIDLendID_11_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 11 THEN Price END), 0),
CurrencyIDLendID_12_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 12 THEN Price END), 0),
CurrencyIDLendID_13_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 13 THEN Price END), 0),
CurrencyIDLendID_21_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 21 THEN Price END), 0),
CurrencyIDLendID_22_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 22 THEN Price END), 0),
CurrencyIDLendID_23_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 23 THEN Price END), 0),
CurrencyIDLendID_31_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 31 THEN Price END), 0),
CurrencyIDLendID_32_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 32 THEN Price END), 0),
CurrencyIDLendID_33_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 33 THEN Price END), 0),
CurrencyIDLendID_41_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 41 THEN Price END), 0),
CurrencyIDLendID_42_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 42 THEN Price END), 0),
CurrencyIDLendID_43_Price = COALESCE(SUM(CASE CurrencyIDLendID WHEN 43 THEN Price END), 0)
FROM cidlid
GROUP BY ID
If all the (CurrencyID, LendID) combinations are guaranteed to be unique within same ID groups, you can also use MIN or MAX instead of SUM.
You could use the PIVOT Syntax starting with SQL Server 2005
Declare #Data table (ID int, CurrencyID int, LendID int , price decimal (4,2))
INSERT INTO #Data
SELECT 3 as ID, 1 as CurrencyID, 1 as LendID , 1.2 as price
UNION SELECT 3 , 1 , 1 , 1.2
UNION SELECT 3 , 1 , 2 , 1.3
UNION SELECT 3 , 1 , 3 , 1.4
UNION SELECT 3 , 2 , 1 , 1.5
UNION SELECT 3 , 2 , 2 , 1.6
UNION SELECT 3 , 2 , 3 , 1.7
UNION SELECT 4 , 2 , 3 , 2.0
SELECT
ID,
COALESCE([1_1],0) as CurrencyIDLendID_11_Price ,
COALESCE([1_2],0) as CIDID_12_Price ,
COALESCE([1_3],0) as CIDLID_13_Price ,
COALESCE([2_1],0) as CIDLID_21_Price ,
COALESCE([2_2],0) as CIDLID_22_Price ,
COALESCE([2_3],0) as CIDLID_23_Price ,
COALESCE([3_1],0) as CIDLID_31_Price ,
COALESCE([3_2],0) as CIDLID_32_Price ,
COALESCE([3_3],0) as CIDLID_33_Price ,
COALESCE([4_1],0) as CIDLID_41_Price ,
COALESCE([4_2],0) as CIDLID_42_Price ,
COALESCE([4_3],0) as CIDLID_43_Price
FROM (
SELECT
ID,
cast(CurrencyID as varchar) + '_' + CAST(lendID as varchar) ColumnHeader,
price FROM #Data ) src
PIVOT (SUM(price) for ColumnHeader IN
([1_1], [1_2],[1_3],
[2_1], [2_2],[2_3],
[3_1], [3_2],[3_3],
[4_1], [4_2],[4_3])
) as pivottable
which outputs
ID CurrencyIDLendID_11_Price CIDID_12_Price CIDLID_13_Price CIDLID_21_Price CIDLID_22_Price CIDLID_23_Price CIDLID_31_Price CIDLID_32_Price CIDLID_33_Price CIDLID_41_Price CIDLID_42_Price CIDLID_43_Price
----------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- --------------------------------------- ---------------------------------------
3 1.20 1.30 1.40 1.50 1.60 1.70 0.00 0.00 0.00 0.00 0.00 0.00
4 0.00 0.00 0.00 0.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00
Note: I kept your column names

Resources