Combining 2 temp queries into 1 - sql

I have tried combining 2 queries into 1. However, I ran into some problems:
exec(#sql + #sql2 + #sql3)
exec(#sql4 + #sql5 + #sql6)
Executing the above, I have the following results:
However, since I would like to combine the 2 queries into 1 using date, I wrote a few more lines as followed:
--Join the 2 queries together for comparison
select a.stime as Date,
a.bid as BidA,
a.ask as AskA,
b.bid as BidB,
b.ask as AskB,
ABS(ISNULL(a.bid, 0) - ISNULL(b.bid, 0)) as BidDiff,
ABS(ISNULL(a.ask, 0) - ISNULL(b.ask, 0)) as AskDiff
from (exec(#sql + #sql2 + #sql3)) a left outer join (exec(#sql4 + #sql5 + #sql6)) b where a.stime = b.stime
Order by date DESC;
However, I kept getting an incorrect syntax error nearby exec.

Create 2 table variables (not sure what your data types are):
DECLARE #tableA AS TABLE([stime] AS datetime, [Bid] AS blah, [Ask] AS blah)
DECLARE #tableB AS TABLE([stime] AS datetime, [Bid] AS blah, [Ask] AS blah)
INSERT INTO #tableA
EXEC (#sql + #sql2 + #sql3)
INSERT INTO #tableB
EXEC (#sql4 + #sql5 + #sql6)
SELECT
[A].[stime] AS [Date]
, [A].[Bid] AS [BidA]
, [A].[Ask] AS [AskA]
, [B].[Bid] AS [BidB]
, [B].[Ask] AS [AskB]
, ABS(ISNULL([A].[Bid], 0) - ISNULL([B].[Bid], 0)) AS [BidDiff]
, ABS(ISNULL([A].[Ask], 0) - ISNULL([B].[Ask], 0)) AS [AskDiff]
FROM #TableA AS [A]
LEFT JOIN #TableB AS [B]
ON [A].[stime] = [B].[stime]
ORDER BY [A].[stime] DESC

Related

Wanted to select from a table but it's ignoring it

I want to have a select statement that takes a table parameter of IDs. The desired behavior is that if there are no elements in the table, get all of the values but if there are elements in the table, only select those who's values match the ID parameter of the table.
My where clause looks like this:
SELECT * FROM BLAH
WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate AND
((SELECT COUNT(ID) FROM #LocationIds) = 0) OR (EXISTS (SELECT 1 FROM
#LocationIds WHERE t.LocationId = ID))
However, the result is always bringing back all locations even where the LocationIds table contains one value and that ID matches only one value.
I can set the values such as, but it still brings back all locations:
DECLARE #LocationIds TABLE
(
ID int
)
INSERT INTO #LocationIds (ID)
VALUES (10227)
Personally, I do this as 2 queries, as the query plan for when there are rows in #LocationIds and is likely to differ enough that the reuse of the plan won't be beneficial to the other, Therefore you get:
IF (SELECT COUNT(*) FROM #LocationIds) = 0 BEGIN
SELECT *
FROM BLAH
WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate;
END ELSE BEGIN
SELECT *
FROM BLAH B
WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate
AND EXISTS (SELECT 1
FROM #LocationIds L
WHERE B.LocationID = L.ID);
END
Alternatively, you could you dynamic SQL to build the query, depending on if the values of #LociationIDs is needed:
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT *' + NCHAR(13) + NCHAR(10) +
N'FROM BLAH B' + NCHAR(13) + NCHAR(10) +
N'WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate' +
CASE WHEN (SELECT COUNT(*) FROM #LocationIds) = 0 THEN ';'
ELSE NCHAR(13) + NCHAR(10) +
N' AND EXISTS (SELECT 1' + NCHAR(13) + NCHAR(10) +
N' FROM #LocationIds L' + NCHAR(13) + NCHAR(10) +
N' WHERE B.LocationID = L.ID);'
END;
EXEC sp_executesql #SQL, N'#BeginTransDate date, #EndTransDate date', #BeginTransDate = #BeginTransDate, #EndTransDate = #EndTransDate;
Note I have guessed that #BeginTransDate and #EndTransDate are a date, and not a datetime. If they are the latter, then that query is unlikely to work as you want anyway, and you would be better of using the logic below:
WHERE TransactionDateTime >= #BeginTransDate
AND TransactionDateTime < DATEADD(DAY, 1, #EndTransDate)
You are missing a pair brackets.
WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate AND
( ((SELECT COUNT(ID) FROM #LocationIds) = 0) OR (EXISTS (SELECT 1 FROM
#LocationIds WHERE t.LocationId = ID)) )
LEFT JOIN might be a simpler solution.
SELECT b.*
FROM BLAH b
LEFT JOIN #LocationIds l ON l.ID = b.LocationId
Try this:
SELECT *
FROM BLAH
WHERE [TransactionDateTime] BETWEEN #BeginTransDate AND #EndTransDate
AND (
(SELECT COUNT(ID) FROM #LocationIds) = 0
OR
ID in (SELECT ID FROM #LocationIds)
)

2005 SSRS/SQL Server PIVOT results need reversing

Preamble: I've read through the three questions/answers here,here, and here, with big ups to #cade-roux. This all stemmed from trying to use the following data in a 2005 SSRS matrix that, I believe, doesn't work because I want to show a member having to take a test multiple times, and SSRS seems to require the aggregate where I want to show all dates.
I get the following results in my table, which seems to be showing all the data correctly:
How do I change the code below to show a) the "tests" at the top of each column with b) if it's called for, the multiple dates that test was taken?
Here's the code I have to produce the table, above. Much of it is commented out as I was just trying to get the pivot to work, but you may notice I am also trying to specify which test column comes first.
CREATE TABLE #tmp ( ---THIS WORKS BUT TESTS ARE VERTICAL
[TEST] [varchar](30) NOT NULL,
[ED] [datetime] NOT NULL
)
--WHERE THE TEST AND ED COME FROM
INSERT #TMP
SELECT DISTINCT
-- N.FULL_NAME
-- , CONVERT(VARCHAR(30), AM.CREATEDATE, 101) AS ACCOUNT_CLAIMED
-- , N.EMAIL
-- , NULL AS 'BAD EMAIL'
-- , CONVERT(VARCHAR(30), AC.EFFECTIVE_DATE, 101) AS EFFECTIVE_DATE
AC.PRODUCT_CODE AS TEST
, CONVERT(VARCHAR(30), AC.EFFECTIVE_DATE, 101) AS ED
-- , CASE
-- WHEN AC.PRODUCT_CODE = 'NewMem_Test' THEN '9'
-- WHEN AC.PRODUCT_CODE = 'NM_Course1' THEN '1'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course1' THEN '2'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course2' THEN '3'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course3' THEN '4'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course4' THEN '5'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course5' THEN '6'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course6' THEN '7'
-- WHEN AC.PRODUCT_CODE = 'NMEP_Course7' THEN '8'
-- END AS 'COLUMN_ORDER'
FROM NAME N
JOIN USERMAIN UM
ON N.ID = UM.CONTACTMASTER
JOIN formTransLog TL
ON UM.USERID = TL.USERNAME
JOIN anet_Users AU
ON UM.USERID = AU.USERNAME
JOIN anet_Membership AM
ON AU.USERID = AM.USERID
JOIN ACTIVITY AC
ON N.ID = AC.ID
AND AC.ACTIVITY_TYPE = 'COURSE'
AND AC.PRODUCT_CODE LIKE 'N%'
--ORDER BY 1, 7
DECLARE #sql AS varchar(max)
DECLARE #pivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #select_list AS varchar(max) -- Leave NULL for COALESCE technique
SELECT #pivot_list = COALESCE(#pivot_list + ', ', '') + '[' + CONVERT(varchar, PIVOT_CODE) + ']'
,#select_list = COALESCE(#select_list + ', ', '') + '[' + CONVERT(varchar, PIVOT_CODE) + '] AS [col_' + CONVERT(varchar, PIVOT_CODE) + ']'
FROM (
SELECT DISTINCT PIVOT_CODE
FROM (
SELECT TEST, ED, ROW_NUMBER() OVER (PARTITION BY TEST ORDER BY ED) AS PIVOT_CODE
FROM #tmp
) AS rows
) AS PIVOT_CODES
SET #sql = '
;WITH p AS (
SELECT TEST, ED, ROW_NUMBER() OVER (PARTITION BY TEST ORDER BY ED) AS PIVOT_CODE
FROM #tmp
)
SELECT TEST, ' + #select_list + '
FROM p
PIVOT (
MIN(ED)
FOR PIVOT_CODE IN (
' + #pivot_list + '
)
) AS pvt
'
PRINT #sql
EXEC (#sql)
EDIT:
The goal is to have the report in SSRS look like this:
I was able to produce the results you were looking for by adding in a number (RowNum) to the query underneath the PIVOT operator. It doesn't have to be in the final query (though you might want it for client-side sorting), but by having it in the underlying layer the PIVOT operation treats that number like a member of a GROUP BY clause.
Please look through my sample SQL below and let me know if this matches your criteria.
CREATE TABLE #TMP
(
Name VARCHAR(10),
Test VARCHAR(20),
EffectiveDate DATETIME
)
INSERT INTO #TMP (Name, Test, EffectiveDate)
SELECT 'Jane', 'NM_Course1', '01/17/2014' UNION
SELECT 'Jane', 'NMEP_Course1', '12/19/2013' UNION
SELECT 'Jane', 'NMEP_Course1', '12/20/2013' UNION
SELECT 'Jane', 'NMEP_Course2', '12/19/2013' UNION
SELECT 'Jane', 'NMEP_Course2', '12/22/2013' UNION
SELECT 'Jane', 'NMEP_Course2', '01/05/2014' UNION
SELECT 'John', 'NM_Course1', '01/17/2014' UNION
SELECT 'John', 'NMEP_Course1', '01/11/2014'
DECLARE #sql AS varchar(max)
DECLARE #pivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE #select_list AS varchar(max) -- Leave NULL for COALESCE technique
SELECT #pivot_list = COALESCE(#pivot_list + ', ', '') + '[' + CONVERT(varchar, PIVOT_CODE) + ']'
,#select_list = COALESCE(#select_list + ', ', '') + '[' + CONVERT(varchar, PIVOT_CODE) + '] AS [col_' + CONVERT(varchar, PIVOT_CODE) + ']'
FROM (
SELECT DISTINCT PIVOT_CODE
FROM (
SELECT TEST AS PIVOT_CODE
FROM #tmp
) AS rows
) AS PIVOT_CODES
SET #sql = '
SELECT Name, ' + #select_list + '
FROM
(
SELECT b.Name, RowNum, b.EffectiveDate, b.TEST AS PIVOT_CODE
FROM
(
SELECT Name, Test, EffectiveDate, ROW_NUMBER() OVER (PARTITION BY NAME, TEST ORDER BY EffectiveDate) RowNum
FROM #Tmp
) b
) p
PIVOT (
MIN(EffectiveDate)
FOR PIVOT_CODE IN (
' + #pivot_list + '
)
) AS pvt
ORDER BY Name, RowNum
'
PRINT #sql
EXEC (#sql)
DROP TABLE #TMP

sql query including month columns?

I was wondering if I could get some ideas or direction on a sql query that would output column months. Here is my current query..
select A.assetid, A.Acquisition_Cost, B.modepreciaterate from FA00100 A
inner join FA00200 B on A.assetindex = B.assetindex
where MoDepreciateRate != '0'
I would like to add more columns that look as such:
select assetid, acquisition_cost, perdeprrate, Dec_2012, Jan_2013, Feb_2013....
where Dec_2012 = (acquisition_cost - MoDepreciateRate*(# of months))
and Jan_2013 = (acquisition_cost - MoDepreciateRate*(# of months))
where # of months can be changed.
Any help would be really appreciated. Thank you!
Here is an example of what I would like the output to be with '# of months' = 4
assetid SHRTNAME Acquisition_Cost perdeprrate Dec_2012 Jan_2013 Feb_2013 Mar_2013
CS-013 GEH INTEG 17490.14 485.83 17004.31 16518.48 16032.65 15546.82
CS-014 WEB BRD 14560 404.4507 14155.5493 13751.0986 13346.6479 12942.1972
Try This:
--setup
create table #fa00100 (assetId int, assetindex int, acquisitionCost int, dateAcquired date)
create table #fa00200 (assetIndex int, moDepreciateRate int, fullyDeprFlag nchar(1), fullyDeprFlagBit bit)
insert #fa00100
select 1, 1, 100, '2012-01-09'
union select 2, 2, 500, '2012-05-09'
insert #fa00200
select 1, 10, 'N', 0
union select 2, 15, 'Y', 1
.
--solution
create table #dates (d date not null primary key clustered)
declare #sql nvarchar(max)
, #pivotCols nvarchar(max)
, #thisMonth date
, #noMonths int = 4
set #thisMonth = cast(1 + GETUTCDATE() - DAY(getutcdate()) as date)
select #thisMonth
while #noMonths > 0
begin
insert #dates select DATEADD(month,#noMonths,#thisMonth)
set #noMonths = #noMonths - 1
end
select #sql = ISNULL(#sql + NCHAR(10) + ',', '')
--+ ' A.acquisitionCost - (B.moDepreciateRate * DATEDIFF(month,dateAcquired,''' + convert(nvarchar(8), d, 112) + ''')) ' --Original Line
+ ' case when A.acquisitionCost - (B.moDepreciateRate * DATEDIFF(month,dateAcquired,''' + convert(nvarchar(8), d, 112) + ''')) <= 0 then 0 else A.acquisitionCost - (B.moDepreciateRate * DATEDIFF(month,dateAcquired,''' + convert(nvarchar(8), d, 112) + ''')) end ' --new version
+ quotename(DATENAME(month, d) + '_' + right(cast(10000 + YEAR(d) as nvarchar(5)),4))
from #dates
set #sql = 'select A.assetid
, A.acquisitionCost
, B.moDepreciateRate
,' + #sql + '
from #fa00100 A
inner join #fa00200 B
on A.assetindex = B.assetindex
where B.fullyDeprFlag = ''N''
and B.fullyDeprFlagBit = 0
'
--nb: B.fullyDeprFlag = ''N'' has double quotes to avoid the quotes from terminating the string
--I've also included fullyDeprFlagBit to show how the SQL would look if you had a bit column - that will perform much better and will save space over using a character column
print #sql
exec(#sql)
drop table #dates
.
--remove temp tables from setup
drop table #fa00100
drop table #fa00200

need help in writing pivot query to select columns from different select statements

I am using SQL Server 2012, i need help in getting the following output. My table structure is as follows:
declare #TestTable table (MaterialCode char(5), ItemCode char(5), ItemName varchar(50))
insert into #TestTable values ('AA-01', 'A0001', 'iPhone')
insert into #TestTable values ('AA-02', 'A0001', 'iPad')
insert into #TestTable values ('AA-03', 'A0001', 'iPod')
insert into #TestTable values ('AA-01', 'B0001', 'Galaxy Tab')
insert into #TestTable values ('AA-02', 'B0001', 'Galaxy Note')
insert into #TestTable values ('AA-01', 'C0001', 'Nokia Lumnia')
insert into #TestTable values ('AA-02', 'C0001', 'Motorola')
insert into #TestTable values ('AA-03', 'C0001', 'Samsung S3')
insert into #TestTable values ('AA-04', 'C0001', 'Sony')
--select * from #TestTable
select MaterialCode, ItemCode as [A_ItemCode], ItemName as [A_ItemName]
from #TestTable where ItemCode='A0001'
select MaterialCode, ItemCode as [B_ItemCode], ItemName as [B_ItemName]
from #TestTable where ItemCode='B0001'
select MaterialCode, ItemCode as [C_ItemCode], ItemName as [C_ItemName]
from #TestTable where ItemCode='C0001'
And the output i need should produced from the above three select statements, which should be as follows:
As you can see, when there is no record, NULLs are displayed there. Can anyone help me getting this output. TIA.
EDIT
#JohnLBevan, I tried your pivot approach and when I have another record which is has ItemCode = D0001
insert into #TestTable values ('AA-05', 'D0001', 'Test1')
now even that record is being displayed as
AA-05 NULL NULL NULL NULL NULL NULL
How to avoid these type of records.
Not using a pivot, but this gives you the desired results:
SELECT coalesce(a.MaterialCode, b.MaterialCode, c.MaterialCode) MaterialCode
, a.ItemCode A_ItemCode
, a.ItemName A_ItemName
, b.ItemCode B_ItemCode
, b.ItemName B_ItemName
, c.ItemCode C_ItemCode
, c.ItemName C_ItemName
FROM (select * from #TestTable where ItemCode='A0001') a
full outer join (select * from #TestTable where ItemCode='B0001') b
on a.MaterialCode = b.MaterialCode
full outer join (select * from #TestTable where ItemCode='C0001') c
on a.MaterialCode = c.MaterialCode
or b.MaterialCode = c.MaterialCode
Here's an alternate which uses a pivot, though this feels messier:
SELECT MaterialCode
, case when [A0001] is null then null else 'A0001' end A_ItemCode
, [A0001] A_ItemName
, case when [A0001] is null then null else 'B0001' end B_ItemCode
, [B0001] B_ItemName
, case when [A0001] is null then null else 'C0001' end C_ItemCode
, [C0001] C_ItemName
FROM #TestTable a
pivot (
max(ItemName)
for ItemCode in ([A0001],[B0001],[C0001])
) pvt
EDIT
If you want something a little more flexible, here's a dynamic version:
declare #dynamicSql nvarchar(max)
, #dynamicSqlPart nvarchar(max)
select * into #TestTable from #TestTable
set #dynamicSql = 'SELECT MaterialCode ' + CHAR(10)
select #dynamicSql = #dynamicSql + ', case when [' + ItemCode + '] is null then null else ''' + ItemCode + ''' end ' + ItemCode + '_ItemCode ' + CHAR(10)
+ ', ' + QUOTENAME(ItemCode) + ' ' + ItemCode + '_ItemName ' + CHAR(10)
, #dynamicSqlPart = ISNULL(#dynamicSqlPart + ',','') + QUOTENAME(ItemCode)
from (select distinct ItemCode from #TestTable) x
set #dynamicSql = #dynamicSql + 'from #TestTable a' + CHAR(10)
+ 'pivot (' + CHAR(10)
+ ' max(ItemName) ' + CHAR(10)
+ ' for ItemCode in (' + #dynamicSqlPart + ')' + CHAR(10)
+ ') pvt' + CHAR(10)
print isnull(#dynamicSql,'?')
exec (#dynamicSql)
drop table #TestTable

Dynamic SQL in Stored Procedure - Datetime parameters

Got a Stored Procedure that has is being converted to Dynamic SQL, the reason is because additional SQL will be passed into the procedure from an external system, before it is executed.
Conversion failed when converting datetime from character string.
Here is the full Stored Procedure:
USE [DBName];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
ALTER PROCEDURE [DB_Admin].[GetMiniCalendarDataNew]
#userID int, #startDate datetime, #endDate datetime, #JVID int = 0
WITH EXEC AS CALLER
AS
set nocount on
declare #SQLQuery AS NVARCHAR(max)
declare #t as table([day] int, [end] datetime, sortorder int, jv int)
SET #SQLQuery= 'insert into #t([day], [end], sortorder, jv)
select day((A.STARTTIME)) [day], max(a.endtime) ''end'', 3 sortorder,min(a.jv) jv
from DB_Admin.CSTM_CALENDAR a
join DB_Admin.CSTM_CALENDAR b on a.id<>b.id
join DB_Admin.CSTM_CALENDARParticipants m1 on a.id=m1.CalendarID
join DB_Admin.CSTM_CALENDARParticipants m2 on b.id=m2.CalendarID
join DB_Admin.DTree DTree on a.FolderDataID=DTree.DataID
where a.starttime between ' + CAST(#startDate AS DATETIME) + ' AND ' + CAST(#endDate AS DATETIME) +
' AND DTree.OwnerID > 0
and b.starttime between ' + CAST(#startDate AS DATETIME) + ' AND ' + CAST(#endDate AS DATETIME) +
' AND a.starttime<b.endtime --find overlapping meetings
AND a.endtime>b.starttime --find overlapping meetings
AND M1.PARTICIPANT IN (
select id from DB_Admin.kuaf where id in (
select id from DB_Admin.kuafchildren
where childid=' +#userID+')
or id=' +#userID+
')
AND M2.PARTICIPANT IN (
select id from DB_Admin.kuaf where id in (
select id from DB_Admin.kuafchildren
where childid='+#userID+')
or id='+#userID+
')'+
--Filter on JV
' AND ( exists (select 1 where a.jv='+#JVID+')
or '+#JVID+'=0'+
')'+
'group by day(A.STARTTIME)'
+' insert into #t ([day], [end], sortorder, jv)
select day(A.STARTTIME) [day], max(a.endtime) ''end'', 2 SORTORDER,min(a.jv) jv
from DB_Admin.CSTM_CALENDAR a
join DB_Admin.CSTM_CALENDAR b on a.id<>b.id
join DB_Admin.CSTM_CALENDARParticipants m1 on a.id=m1.CalendarID
join DB_Admin.CSTM_CALENDARParticipants m2 on b.id=m2.CalendarID
join DB_Admin.DTree DTree on a.FolderDataID=DTree.DataID
where a.starttime between ' + CAST(#startDate AS DATETIME) +' AND ' +CAST(#endDate AS DATETIME)+
' AND DTree.OwnerID > 0
--Filter on JV
AND ( exists (select 1 where a.jv='+#JVID+')
or '+#JVID+'=0'+')
and M1.PARTICIPANT IN (
select id from DB_Admin.kuaf where id in (
select id from DB_Admin.kuafchildren
where childid='+#userID+')
or id='+#userID+
')
group by (A.STARTTIME)'+
' insert into #t ([day], [end], sortorder, jv)
select day(A.STARTTIME) [day], max(a.endtime) ''end'', 1 SORTORDER,min(a.jv) jv
from DB_Admin.CSTM_CALENDAR a
join DB_Admin.CSTM_CALENDARParticipants m1 on a.ID=m1.CalendarID
join DB_Admin.DTree DTree on a.FolderDataID=DTree.DataID
where a.starttime between '+CAST(#startDate AS DATETIME)+' AND '+CAST(#endDate AS DATETIME)+
' AND DTree.OwnerID > 0
--Filter on JV
AND ( exists (select 1 where a.jv='+#JVID+')
or '+#JVID+'=0'+ ')
and M1.PARTICIPANT NOT IN (
select id from DB_Admin.kuaf where id in (
select id from DB_Admin.kuafchildren
where childid='+#userID+')
or id='+#userID+'
)
group by (A.STARTTIME)'
--format query
+' select [day], max(month('+CAST(#startDate AS DATETIME)+' [month], max(year('+CAST(#endDate AS DATETIME)+')) [year], max([end]) ''end'',
case
when max(sortorder)=3 then ''Overlapping''
when max(sortorder)=2 then ''Participating''
when max(sortorder)=1 then ''Existing''
when max(sortorder)=0 then ''Empty''
end sortOrder , min(jv) JVID
from #t
group by [day]
order by sortorder desc'
--EXEC (#SQLQuery)
PRINT (#SQLQuery)
GO
Well, you need to
Quoting them
Ensure they are string
Make them language/locale safe
So:
...
where a.starttime between ''' + CONVERT(varchar(30), #startDate, 126) +''' AND ''' + ...
...
Edit:
int error. You need to CAST #userID to varchar concatenate it.
SQL doesn't do VBA style implicit CASTs
I think your problem is here:
'where a.starttime between ' + CAST(#startDate AS DATETIME) + ' AND ' + CAST(#endDate AS DATETIME) +
You should be converting it to a string, rather than a datetime. See http://msdn.microsoft.com/en-us/library/ms187928.aspx