CREATE PROCEDURE [dbo].[spReport]
#FromDate DATETIME = NULL,
#ToDate DATETIME = NULL,
#TenantID int ,
#BusinessUnitId int
AS
BEGIN
Declare #listStr Varchar(max), #listValue Varchar(max)
Select
#listStr = COALESCE(#listStr+',' ,'') + FieldLabel
From
(Select Distinct Top 100
FieldLabel, ControlTypeId
From
PaymentCustomFieldDefinitions PCFD
Inner Join
Product P On P.Id = PCFD.ProductId
Where
P.TenantId = #TenantId
Order By
ControlTypeId Desc) R
Set #listStr = ',' + #listStr
Set #listStr = IsNull(#listStr, '')
Select
'Confirmation Number,Business Unit,Bank Account,Merchant Account,Product Name,Payment Date,Payment Time,Total Amount,Status,First Name,Last Name,Payment Method' + #listStr
Union
SELECT
p.ConfirmationNumber + ',' + bu.Name + ',' + p.TenantBankAccountName + ',' + Case When ma.Name IS NULL then '' ELSE ma.Name END + ',' + pd.Name + ',' +
cast(P.PaymentDate as Varchar(11)) + ',' + convert(VARCHAR(8), P.PaymentDate,108) + ',' + Cast(p.TotalDue As Varchar(20)) + ',' + p.PaymentStatusText + ',' + p.PayorFirstName + ',' + p.PayorLastName + ',' + p.PaymentMethodText + ',' + [dbo].[GetPaymentReferenceAndCustomFields](p.Id,#listStr)
FROM
Payment p
INNER JOIN
Product pd ON p.ProductId = pd.Id
INNER JOIN
BusinessUnit bu ON pd.BusinessUnitId = bu.Id
INNER JOIN
ProductDetailPayment pdp ON p.ProductId = pdp.ProductId
LEFT OUTER JOIN
MerchantAccount ma ON ma.Id = pdp.MerchantAccountId
WHERE
p.PaymentDate BETWEEN #FromDate AND #ToDate
AND p.TenantId = #TenantId AND pd.BusinessUnitId= #BusinessUnitId
ORDER BY
p.ProductId desc
END
Getting this error when using Order by :
Msg 4104, Level 16, State 1, Procedure spReport, Line 41
The multi-part identifier "p.ProductId" could not be bound.
Msg 104, Level 16, State 1, Procedure spQueryPaymentDetailReport, Line 41
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
You can't reference p.ProductId in the ORDER BY because the first subquery doesn't have a p dataset.
You can't reference a ProductId column in the ORDER BY because there's no column by that name in the combined result set.
To solve these issues, you could add a ProductId column and, if the final output must contain a single column like in your query, use a derived table:
SELECT
p.CSV
FROM (
Select
ProductId = 2147483647,
CSV = 'Confirmation Number,Business Unit,Bank Account,Merchant Account,Product Name,Payment Date,Payment Time,Total Amount,Status,First Name,Last Name,Payment Method' + #listStr
Union
SELECT
p.ProductId,
p.ConfirmationNumber + ',' + bu.Name + ',' + p.TenantBankAccountName + ',' + Case When ma.Name IS NULL then '' ELSE ma.Name END + ',' + pd.Name + ',' +
cast(P.PaymentDate as Varchar(11)) + ',' + convert(VARCHAR(8), P.PaymentDate,108) + ',' + Cast(p.TotalDue As Varchar(20)) + ',' + p.PaymentStatusText + ',' + p.PayorFirstName + ',' + p.PayorLastName + ',' + p.PaymentMethodText + ',' + [dbo].[GetPaymentReferenceAndCustomFields](p.Id,#listStr)
FROM
Payment p
INNER JOIN
Product pd ON p.ProductId = pd.Id
INNER JOIN
BusinessUnit bu ON pd.BusinessUnitId = bu.Id
INNER JOIN
ProductDetailPayment pdp ON p.ProductId = pdp.ProductId
LEFT OUTER JOIN
MerchantAccount ma ON ma.Id = pdp.MerchantAccountId
WHERE
p.PaymentDate BETWEEN #FromDate AND #ToDate
AND p.TenantId = #TenantId AND pd.BusinessUnitId= #BusinessUnitId
) p
ORDER BY
p.ProductId desc
;
The first row is assigned the MaxInt ID value because, as I understand, it is the header row and must go first according to the specified ORDER BY p.ProductId DESC clause (and because I've assumed the ProductId is an int, of course).
Related
Relatively straight forward question but I am a novice with SQL queries. I'm trying to find in all the tables any record that contains a certain value.
So in a nutshell I want to find in the entire database any instance where the hContactId is 200.
I've tried the following:
USE dbname
SELECT *
FROM sys.Tables
WHERE hContacts.hContactId = 200;
I end up with
You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version
I've seen some really complex queries like below that didn't work but surely there should be a way to query all tables for an integer right?
Another thing I tried to the same error message:
declare #sql varchar(8000), #tbl varchar(255), #col varchar(255),
#data varchar(50)
set #data = '200'
declare cur_tbl cursor for
select a.name, b.name from sysobjects a, syscolumns b, systypes c where a.id = b.id and a.type = 'U' and c.xtype = b.xtype and c.name in ( 'int' )
open cur_tbl
fetch next from cur_tbl into #tbl, #col
while ##fetch_status = 0
begin
set #sql = '
if exists (select * from [' + #tbl + '] where convert( varchar(255), [' + #col + '] ) = ''' + #data + ''')
select tbl=''' + #tbl + ''', col=''' + #col + ''', [' + #col + '], * from [' + #tbl + '] where convert( varchar(255), [' + #col + '] ) = ''' + #data + '''
'
exec(#sql)
fetch next from cur_tbl into #tbl, #col
end
close cur_tbl
deallocate cur_tbl
Again just looking for a basic query on all tables looking for those that match the hContactId. Any ideas?
Well you can always use a union:
SELECT * FROM Table_name_1
WHERE hContactId = 200;
UNION
SELECT * FROM Table_name_2
WHERE hContactId = 200;
UNION
SELECT * FROM Table_name_3
WHERE hContactId = 200;
Can anybody tell me why the second LEFT JOIN in the query below (previous_spend) is returning double the amount it should?
It returns the correct amount if I remove the first LEFT JOIN, so I assume it's doubling the result due to the first LEFT JOIN, but I'm not sure how to rewrite the query to avoid that.
Any help would be much appreciated.
Update: I've created a slightly easier to understand version here: Here's a live example: http://sqlfiddle.com/#!9/6a9358/1 - as you can see 'current_spend' should return £300.
SELECT
COALESCE(SUM(current_spend.total_spend), 0) AS total_spend,
COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_previous_spend,
COALESCE(SUM(current_spend.total_spend), 0) - COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_spend_diff,
100 * (COALESCE(SUM(current_spend.total_spend), 0) - COALESCE(SUM(previous_spend.total_previous_spend), 0)) / COALESCE(SUM(previous_spend.total_previous_spend), 0) AS total_spend_diff_perc
FROM customer_scheme
LEFT JOIN (
SELECT SUM(spend_1 + spend_2) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2017'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2018'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2019'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2) AS total_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2020'
GROUP BY user_id
) as current_spend
ON current_spend.user_id = customer_scheme.user_id
LEFT JOIN
(
SELECT SUM(spend_1 + spend_2) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2013'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2014'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2015'
GROUP BY user_id
UNION ALL
SELECT SUM(spend_1 + spend_2) AS total_previous_spend, user_id
FROM customer_spend
WHERE customer_spend.spend_year = '2016'
GROUP BY user_id
) as previous_spend
ON previous_spend.user_id = customer_scheme.user_id
LEFT JOIN user
ON customer_scheme.user_id = user.user_id
WHERE customer_scheme.scheme_id = 36
AND customer_scheme.customer_scheme_access = 'Yes'
AND user.user_deleted_at IS NULL
AND user_type = 'Customer'
AND user.user_status IN (1)
ORDER BY total_spend_diff DESC
The summary of your query is
(customer_scheme LEFT JOIN current_spend) appended with (customer_scheme LEFT JOIN previous_spend)
If you remove the LEFT JOIN with current_spend :
Query would be customer_scheme LEFT JOIN previous_spend
That means, for one user in customer_scheme, you will get one row for previous_spend for 2013, one row for 2014, one row for 2015, one row for 2016
While summing, you will sum all the above said 4 rows.
If you have the LEFT JOIN with current_spend :
For first LEFT JOIN with current_spend, you will get one row for 2017, one for 2018, one for 2019 and one for 2020.
So, for one user_id , you will get 4 rows. Now, you are going to join previous_spend with these 4 rows (where as previously, you will join with only one row). While summing, this makes the difference.
I will try to provide much better insights if you can share an sql fiddle with some test data.
Try this:
SELECT
SUM(IFNULL(current_spend.total_spend, 0)) AS total_spend,
SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_previous_spend,
SUM(IFNULL(current_spend.total_spend, 0)) - SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_spend_diff,
100 * (SUM(IFNULL(current_spend.total_spend, 0)) - SUM(IFNULL(previous_spend.total_previous_spend, 0))) / SUM(IFNULL(previous_spend.total_previous_spend, 0)) AS total_spend_diff_perc
FROM
customer_scheme
LEFT JOIN
(
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_spend, user_id, customer_spend.spend_year
FROM customer_spend
WHERE customer_spend.spend_year in ('2017','2018','2019','2020')
GROUP BY user_id, customer_spend.spend_year
) as current_spend
ON current_spend.user_id = customer_scheme.user_id
INNER JOIN
(
SELECT SUM(spend_1 + spend_2 + spend_3 + spend_4 + spend_5 + spend_6 + spend_7 + spend_8 + spend_9 + spend_10 + spend_11 + spend_12) AS total_previous_spend, user_id, customer_spend.spend_year
FROM customer_spend
WHERE customer_spend.spend_year in ('2013','2014','2015','2016')
GROUP BY user_id, customer_spend.spend_year
) as previous_spend
ON previous_spend.user_id = customer_scheme.user_id
LEFT JOIN user
ON customer_scheme.user_id = user.user_id
WHERE customer_scheme.scheme_id = 36
AND customer_scheme.customer_scheme_access = 'Yes'
AND user.user_deleted_at IS NULL
AND user_type = 'Customer'
AND user.user_status IN (1)
ORDER BY total_spend_diff DESC;
I want to run a query that shows me all columns from all tables in a database with the datatype varchar and a maximum length of 8000 characters.
This is my code so far.
DECLARE #tabs VARCHAR(MAX);
SET #tabs =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #cols VARCHAR(MAX)
SET #cols =
(
SELECT STUFF(( SELECT DISTINCT ',' + [TABLE_NAME] + '.' + [COLUMN_NAME]
FROM [DB-Test].INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'VARCHAR' AND
CHARACTER_MAXIMUM_LENGTH = 8000
FOR XML PATH('')), 1, 1, '')
);
DECLARE #query VARCHAR(MAX) = 'SELECT ' + #cols + ' FROM ' + #tabs
EXEC sp_sqlexec #query
When I run the query I get all the column names, but not the values in the columns. It's empty. No 'NULL'-values. As if #cols is interpreted as simple string maybe.
Why?
(When I read out #cols and #tabs they are correct.)
I guess there is one table available in your database which have column with VARCHAR datatype and 8000 length but that table don't have any records. Try by including only those column and table which have at least one record available.
You can try below. Check it and let me know if it works.
DECLARE #tabs VARCHAR(MAX) = ''
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #tabs = #tabs+ISNULL(','+TABLE_NAME, '')
FROM TABLENAME
DECLARE #cols VARCHAR(MAX) = '';
; WITH CTE AS
(
SELECT DISTINCT TA.NAME TABLENAME
, SUM(PA.ROWS) OVER (PARTITION BY TA.NAME ) NOOFROW
FROM SYS.TABLES TA
INNER JOIN SYS.PARTITIONS PA ON PA.OBJECT_ID = TA.OBJECT_ID
INNER JOIN SYS.SCHEMAS SC ON TA.SCHEMA_ID = SC.SCHEMA_ID
WHERE TA.IS_MS_SHIPPED = 0 AND PA.INDEX_ID IN (1,0)
), TABLENAME AS
(
SELECT ITBL.[TABLE_NAME], ITBL.[COLUMN_NAME]
FROM INFORMATION_SCHEMA.COLUMNS ITBL
WHERE ITBL.DATA_TYPE = 'VARCHAR' AND
ITBL.CHARACTER_MAXIMUM_LENGTH = 8000
AND EXISTS(SELECT 1 FROM CTE WHERE CTE.TABLENAME = ITBL.TABLE_NAME AND CTE.NOOFROW > 0) -- To check no of record available in table
)
SELECT #cols = #cols+ISNULL(','+[TABLE_NAME]+'.'+[COLUMN_NAME], '')
FROM TABLENAME
IF LEN(#cols) > 0 AND LEN(#tabs) > 0
BEGIN
DECLARE #query VARCHAR(MAX) = 'SELECT ' + STUFF(#cols,1,1,'') + ' FROM ' + STUFF(#tabs,1,1, '')
EXEC sp_sqlexec #query
END
ELSE
BEGIN
PRINT 'No Column available with data where it''s datatype is VARCHAR and length is 8000'
END
I have two tables. One has products and the other has bundles that go with it. I need to figure out the SQL that allows me to find all the combinations in which I can sell the product with extras.
Products
Name ID
Bench 1
Extra
Name ID Parent ID QTY
undershelf 1 1 1
overshelf 2 1 1
wheels 3 1 1
I need and output table that shows all the combination in which I can sell the product:
Bench
Bench + undershelf
Bench + undershelf + overshelf
Bench + overshelf
Bench + wheels
bench + wheels + overshelf and so one.
Every extras can be in the bundle or not, making that a binary property.
A way to visualize the combination is to create a word with a bit for every extra, 1 mean that the extra is in the list, 0 mean the that it is not.
For example Bench + undershelf + overshelf is 110 (or 011 if the binary string is read in the opposite order)
Generating every combination of n bit will give every combination of n extras, it will also give every number from 0 to 2^n - 1.
We can work back from here:
1. generate the list of number from 0 to 2^n - 1;
2. convert the number to binary, to list the combination of extras
3. match every bit with an extra
4. concatenate the names of the extras in the bundle description.
SELECT CONCAT(b.Name
, COALESCE(CONCAT(' + '
, GROUP_CONCAT(x.Name SEPARATOR ' + '))
, '')) Combination
FROM (SELECT p.Name, p.id
, LPAD(BIN(u.N + t.N * 10), e.Dim, '0') bitmap
FROM Products p
CROSS JOIN (SELECT 0 N UNION ALL SELECT 1
UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9) u
CROSS JOIN (SELECT 0 N UNION ALL SELECT 1
UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9) t
INNER JOIN (SELECT COUNT(1) Dim
, `Parent ID` pID
FROM Extra) E ON e.pID = p.ID
WHERE u.N + t.N * 10 < Pow(2, e.Dim)
) B
LEFT JOIN (SELECT #rownum := #rownum + 1 ID
, `Parent ID` pID
, Name
FROM Extra
, (Select #rownum := 0) r) X
ON x.pID = b.ID
AND SUBSTRING(b.bitmap, x.ID, 1) = '1'
GROUP BY b.Name, b.bitmap
this query will work up to six extras, then it'll need another digit table (one digit every three extras).
How it Works
The subquery E count the number of the extras, this is used in C to limit the elements generated by the digit tables u and t (unit and tens) to 2^dim.
The number is converted to binary by BIN(u.N + t.N * 10), then left padded with '0' to the number of elements, generating a combination bitmap.
To use the generated bitmap each extras need a fake id that will match a position in it, that's what the subquery X is meant for.
The two subqueries are JOINed by the nth char of the bitmap: if the char is 1 the extra is in the bundle, LEFT joined to not loose the product without extras.
I cannot think of any ingenious way of doing this in mysql, but it is very easy in a scripting language. Here in PHP:
<?php
$extra = array('undershelf', 'overshelf', 'sheels');
$possible_combinations = pow(2, count($extra));
for ($i = 0; $i < $possible_combinations; $i++) {
$combo = array('Bench');
foreach ($extra as $j => $item) {
if ($i & pow(2, $j)) {
$combo[] = $item;
}
}
echo implode(' + ', $combo) . "\n";
}
prints
Bench
Bench + undershelf
Bench + overshelf
Bench + undershelf + overshelf
Bench + sheels
Bench + undershelf + sheels
Bench + overshelf + sheels
Bench + undershelf + overshelf + sheels
Possible entirely within MySQL, though not simple. This example can handle up to 5 "extras", and is easily extensible for more:
CREATE TABLE products (name varchar(100), id int primary key);
INSERT INTO products (name, id) VALUES ('Bench', 1);
CREATE TABLE extra (name varchar(100), id int primary key, parent_id int references products.id, qty int);
INSERT INTO extra (name, id, parent_id, qty) VALUES
('undershelf', 1, 1, 1), ('overshelf', 2, 1, 1), ('wheels', 3, 1, 1);
CREATE TABLE boolean_values (x boolean);
INSERT INTO boolean_values VALUES (TRUE), (FALSE);
CREATE VIEW product_extras_interim_vw AS
SELECT p.id product_id, p.name product_name, e.id extra_id, e.name extra_name, x
FROM products p
JOIN extra e ON (e.parent_id = p.id)
CROSS JOIN boolean_values;
SELECT DISTINCT a.product_name
, CASE WHEN a.x THEN CONCAT(' + ', a.extra_name) END extra1
, CASE WHEN b.x THEN CONCAT(' + ', b.extra_name) END extra2
, CASE WHEN c.x THEN CONCAT(' + ', c.extra_name) END extra3
, CASE WHEN d.x THEN CONCAT(' + ', d.extra_name) END extra4
, CASE WHEN e.x THEN CONCAT(' + ', e.extra_name) END extra5
FROM product_extras_interim_vw a
LEFT JOIN product_extras_interim_vw b
ON ( a.product_id = b.product_id
AND b.extra_id > a.extra_id
AND a.x )
LEFT JOIN product_extras_interim_vw c
ON ( a.product_id = c.product_id
AND c.extra_id > b.extra_id
AND b.x )
LEFT JOIN product_extras_interim_vw d
ON ( a.product_id = d.product_id
AND d.extra_id > c.extra_id
AND c.x)
LEFT JOIN product_extras_interim_vw e
ON ( a.product_id = e.product_id
AND e.extra_id > d.extra_id
AND d.x)
ORDER BY product_name, extra1, extra2, extra3, extra4, extra5;
Output:
Bench
Bench + overshelf
Bench + overshelf + wheels
Bench + undershelf
Bench + undershelf + overshelf
Bench + undershelf + overshelf + wheels
Bench + undershelf + wheels
Bench + wheels
I have three tables. I need to swith row values into columns.
Table-1: [Approval_Type]
App_ID Type_Ds
2 RMC2
1 RMC1
Table 2: [Project]
Pro_id Summary
1 PROJECT1
2 PROJECT2
Table:3 [Prj_App]
App_Id Pro_Id ExpDt ComDt
1 2 2010-06-05 2010-07-06
1 1 1999-05-05 1999-05-06
2 1 1900-01-01 1900-01-05
I want to display my result as
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 1900-01-01 1900-01-05 RMC1 1999-05-05 1999-05-06
2 NULL NULL NULL RMC1 2010-06-05 2010-07-06
Below is my query which returns'
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + ' Expected Date') + ',' + QUOTENAME(Type_Ds + ' Completed Date')
from dbo.AppType
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #SQL1
SET #SQL = 'SELECT *
FROM ( SELECT A.Pro_Id,
Type_DS
FROM dbo.Project A left join [dbo].[Prj_App] B on A.Pro_id = B.Pro_Id
right outer join dbo.AppType C on B.App_Id = C.App_ID
) data
PIVOT
( MAX(Type_DS)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1
where Pro_Id is not null'
print #SQL
EXECUTE SP_EXECUTESQL #SQL
Pro_Id RMC2 RMC2ExpeDt RMC2ComDt RMC1 RMC1ExpeDt RMC1ComDt
1 RMC2 NULL NULL RMC1 NULL NULL
2 NULL NULL NULL RMC1 NULL NULL.
can anyone help on it...
My suggestion when you are working with dynamic SQL is to always write the query hard-coded first, so you can get the logic correct, then convert it to dynamic SQL.
Since you are attempting to pivot 3 columns of data I would first unpivot the type_ds, expdt and comdt` columns, then apply the PIVOT function.
The hard-coded version of the query will be:
SELECT *
FROM
(
select pro_id,
type_ds = case
when col ='type_ds'
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select 'type_ds', type_ds union all
select 'expdt', expdt union all
select 'comdt', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (RMC2, RMC2expdt, RMC2comdt,
RMC1, RMC1expdt, RMC1comdt)
) pvt1
See SQL Fiddle with Demo. Now that you have a working version of the query, you can easily convert it to dynamic SQL:
DECLARE #SQL1 NVARCHAR(MAX) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL1 = STUFF((SELECT ',' + QUOTENAME(Type_Ds) + ',' + QUOTENAME(Type_Ds + 'ExpDt') + ',' + QUOTENAME(Type_Ds + 'ComDt')
from dbo.Approval_Type
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #SQL = 'SELECT *
FROM
(
select pro_id,
type_ds = case
when col =''type_ds''
then type_ds
else type_ds+col end,
value
from
(
SELECT A.Pro_Id,
c.Type_DS,
convert(varchar(10), b.ExpDt, 120) ExpDt,
convert(varchar(10), b.ComDt, 120) ComDt
FROM dbo.Project A
left join [dbo].[Prj_App] B
on A.Pro_id = B.Pro_Id
right outer join dbo.Approval_Type C
on B.App_Id = C.App_ID
) s
cross apply
(
select ''type_ds'', type_ds union all
select ''expdt'', expdt union all
select ''comdt'', comdt
) c (col, value)
) data
PIVOT
(
MAX(value)
FOR Type_DS IN (' + #SQL1 + ')
) pvt1 '
--print #SQL
EXECUTE SP_EXECUTESQL #SQL
See SQL Fiddle with Demo