I have three tables, SUsers, Questions, and Votes.
-SUsers- have columns:
SID,SHName,EmailAdd,Password,DoneVoting,AccessLevel, and NumberOfShares
-Questions- have columns: QID, and Questions.
-Votes- have columns: VID, SID, QID, VoteDate, and Answer.
The questions are answerable by "In Order", "Against", and "Abstain."
For example, I have user 1 who have NumberOfShares of 100. The user's one vote will be multiplied by 100.
Currenty, I have this working stored procedure that only gets one vote per user. I'm having a difficulty of multiplying it with the NumberOfShares.
Here's my stored proc.
ALTER PROCEDURE [dbo].[sp_VotingTally2]
#dateFrom NVARCHAR(MAX),
#dateTo NVARCHAR(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #columns VARCHAR(MAX)
SELECT #columns = COALESCE(#columns + ',','') + QUOTENAME([QID])
FROM (SELECT [QID] FROM [PressRelease].[dbo].[Questions]) st
ORDER BY st.[QID]
DECLARE #sql NVARCHAR(MAX)
SET #sql =
'SELECT * FROM (
SELECT b.[QID],[Answer],[Answer] as Answers FROM [PressRelease].[dbo].[Votes] a INNER JOIN [PressRelease].[dbo].[Questions] b ON a.QID = b.QID
WHERE [VoteDate] >= CAST('''+ #dateFrom +''' AS DATETIME2) AND [VoteDate] <= CAST('''+ #dateTo +'''AS DATETIME2)
) t
PIVOT
(
COUNT([Answer])
FOR [QID] in (' + #columns + ')
) p
'
EXECUTE sp_executesql #sql
END
Here's the result of this stored proc
I've been trying different approach but all I get is error to get what I want. I would like to multiply all the numbers in these columns to a number from a column in my other table. The column is NumberOfShares. For every voter, they have their number of shares that would be needed to multiply to their votes. I hope you could help me with this.
First let's fix your query first. This part:
SET #sql = '
SELECT ' + #columns + '
FROM (
SELECT b.[QID], a.[Answer]
FROM [PressRelease].[dbo].[Votes] a
INNER JOIN [PressRelease].[dbo].[Questions] b ON a.QID = b.QID
WHERE a.[VoteDate] >= #dFrom AND a.[VoteDate] <= #dTo
) t
PIVOT(COUNT([Answer]) FOR [QID] in (' + #columns + ')) p
'
EXEC sp_executesql #sql, N'#dFrom datetime, #dTo datetime', #dFrom = #dFrom, #dTo = #dTo;
So what do you want to multiply by what?
It would be better to give the structure of that secret table you want to join and multiply but let's assume this is a "Voters" table:
SET #sql = '
SELECT [Answer], ' + #columns + '
FROM (
SELECT a.[Answer], b.[QID], v.[NumberOfShares]
FROM [PressRelease].[dbo].[Votes] a
INNER JOIN [PressRelease].[dbo].[Questions] b ON a.QID = b.QID
INNER JOIN [PressRelease].[dbo].[Voters] v ON a.VoterID = v.VoterID
WHERE a.[VoteDate] >= #dFrom AND a.[VoteDate] <= #dTo
) t
PIVOT(SUM([NumberOfShares]) FOR [QID] in (' + #columns + ')) p
'
EXEC sp_executesql #sql, N'#dFrom datetime, #dTo datetime', #dFrom = #dFrom, #dTo = #dTo;
Related
I need to select all unique values from all columns in a table.
I have tried to implement the query below which I found in the thread How to get unique values from all columns of a table in SQL Server.
declare #Sql_Str varchar(8000)='';
select #Sql_Str=#Sql_Str+' select cast (' +name +' as varchar(500))
from <yourtable> union'
from sys.columns
where [object_id]=object_id('<yourtable>');
set #Sql_Str=SUBSTRING(#Sql_Str,1,len(#Sql_Str)-6);
exec(#Sql_Str)
I cannot get that query to work however. My table has 118 columns. I think that may be more data than the query above may handle.
Try something like this:
DECLARE #Schema VARCHAR(500)='dbo';
DECLARE #tableName VARCHAR(500)='SomeTable';
DECLARE #cmd NVARCHAR(MAX)=
(
SELECT STUFF(
(
SELECT ' UNION ALL SELECT ''' + c.TABLE_SCHEMA + ''' AS TableSchema '
+ ',''' + c.TABLE_NAME + ''' AS TableName '
+ ',''' + c.COLUMN_NAME + ''' AS ColumnName '
+ ',''' + c.DATA_TYPE + ''' AS ColumnType '
+ ',CAST(' + QUOTENAME(c.COLUMN_NAME)+' AS NVARCHAR(MAX)) AS Value '
+ ' FROM ' + QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)
+ ' WHERE ' + QUOTENAME(c.COLUMN_NAME) + ' IS NOT NULL '
+ ' GROUP BY ' + QUOTENAME(c.COLUMN_NAME) + ' '
FROM INFORMATION_SCHEMA.COLUMNS AS c
WHERE TABLE_NAME=#TableName
AND TABLE_SCHEMA=#Schema
--exclude not supported types
--AND c.DATA_TYPE NOT IN('xml') --add more types
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)'),1,10,'')
);
--PRINT #cmd
EXEC(#cmd);
This statement will first create a long list of UNION ALL SELECT with GROUP BY (better than DISTINCT) as dynamically created SQL and executes this with EXEC().
You can decomment PRINT to examine the statement created.
This should work in tSQL:
declare #table_name varchar(55)
set #table_name= 'IV00101' ---- <-- Change this to your table name
create table #colcount (
colname varchar(55),
dct int,
tot int
)
create table #colContent (
colname varchar(55),
col_val nvarchar(max),
col_val_count int
)
create table #sqlexecs( s varchar(max))
declare #col_name varchar(max), #sql nvarchar(max), #sql2 nvarchar(max)
declare c cursor for
select name from sys.columns where [object_id]=object_id(#table_name)
open c
fetch next from c into #col_name
while ##FETCH_STATUS = 0
begin
set #sql = 'select cn.name, count(distinct '+#col_name+') as dct_numrow, count('+#col_name+') as tot_numrow from '+#table_name+' join (select name from sys.columns where name = '''+#col_name+''' and [object_id]=object_id('''+#table_name+''')) cn on cn.name = '''+#col_name+''' group by cn.name'
set #sql2 = 'select ' +#col_name+', count('+#col_name+') as colvalcnt from '+#table_name+' group by '+#col_name
--insert into #sqlexecs values (#sql) --uncomment to view sql selects produced by #sql
--insert into #sqlexecs values (#sql2) --uncomment to view sql selects produced by #sql2
insert into #colcount execute sp_executesql #sql
------
declare #d int, #t int
set #d = (select dct from #colcount where colname = #col_name)
set #t = (select tot from #colcount where colname = #col_name)
if (#d <> #t)
begin
insert into #colContent (colname) values (#col_name)
insert into #colContent (col_val,col_val_count) execute sp_executesql #sql2
end
else
begin
insert into #colContent values (#col_name,1,1)
end
fetch next from c into #col_name
end
close c
deallocate c
--select * from #sqlexecs -- uncomment to view sql code produced by #sql and #sql2
select * from #colcount --order by dct desc
select * from #colContent
drop table #colcount
drop table #colContent
drop table #sqlexecs
The first table shows column name, distinct value count, and total value count.
The second table shows column name, distinct values, and the number of times a distinct value appears. If values in column are all distinct (column is a candidate key), colname | 1 | 1 is shown. This should work if copy/pasted, please let me know it doesn't. Dev for use in Dynamics GP.
In this stored procedure, I have to use
SELECT *
FROM #policyData a
LEFT OUTER JOIN ##Temp b ON b.qguid = a.quoteguid
LEFT OUTER JOIN ##Temp c ON c.qguid = a.quoteguid2;
And because of that I have two columns with the same name "QuoteGuid".
Then when I try to add this query in SSRS, I get an error, because I have 2 columns with the same name.
I am not the author of this stored procedure, so I cannot understand is any chance to eliminate or rename column name that causing this.
CREATE PROCEDURE dbo.SP_Catalytic_WindEQRenewalExtract
#pos INT,
#len INT,
#value varchar(8000),
#PriorDays INT,
#PastDays INT,
#LineName varchar(50)
AS
SET NOCOUNT ON;
SELECT #LineName ='wind'
SELECT #PriorDays= -15
SELECT #PastDays = 55
DECLARE #policyData TABLE
(
NamedInsured varchar(1000),
displaystatus varchar(100),
quoteguid uniqueidentifier,
quoteid int,
controlno int,
ExpirationDate datetime,
MonthName nvarchar(25),
ExpiringPremium money,
Underwriter varchar(250),
linename varchar(25),
RenewalSubmissionRecieved varchar(5),
QuotedPremium money,
quoteguid2 uniqueidentifier,
controlno2 int,
displaystatus2 varchar(50),
quotestatuscomment varchar(2500),
quotestatusreasoncomment varchar(2500),
BoundPremium money,
Underwriter2 varchar(500)
)
INSERT INTO #policyData
EXEC ('Catalytic_sp_FetchRenewalPolicy ' + #PriorDays + ',' + #PastDays + ', ' + #LineName + '')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',' + QUOTENAME(c.locationCode)
FROM Catalytic_vw_LocationCodeByLine c WHERE c.linename =#LineName order by c.CompanyName, c.LocationCode
FOR XML PATH('')),1,1,'')
IF OBJECT_ID('tempdb.dbo.##Temp', 'U') IS NOT NULL
DROP TABLE ##Temp;
set #query =
'select * into ##Temp
from
(SELECT QUOTEGUID as qguid, ' + #cols + ' from
(
select QuoteGUID, LocationCode, LineName,LineGUID
--from Catalytic_vw_PolicyLocationCode where quoteguid=''99D60178-C33B-4A3F-9EA7-0001EF31626A''
from Catalytic_vw_PolicyLocationCode
) x
pivot
(
max(locationCode)
for locationCode in (' + #cols + ')
)p)x'
EXEC sp_executesql #query;
set #pos = 0
set #len = 0
WHILE CHARINDEX(',', #cols, #pos+1)>0
BEGIN
set #len = CHARINDEX(',', #cols, #pos+1) - #pos
set #value = SUBSTRING(#cols, #pos, #len)
-- PRINT #value
set #pos = CHARINDEX(',', #cols, #pos+#len) +1
declare #sql nvarchar (1000);
set #sql = N'update ##Temp set ' + #value + '= ''X'' where len(' + #value + ') > 0 ' ;
exec sp_executesql #sql;
END
SELECT *
FROM
#policyData a
LEFT OUTER JOIN ##Temp b on b.qguid = a.quoteguid
/*Because I am using another LEFT JOIN here, I have two columns namem "qguid"*/
LEFT OUTER JOIN ##Temp c on c.qguid = a.quoteguid2;
DROP TABLE ##Temp;
just change where you are trying to make another left join in the last and explicitly mention all column name.
SELECT a.* ,b.*,c.qguid as qguid1
FROM
#policyData a
LEFT OUTER JOIN ##Temp b on b.qguid = a.quoteguid
/*Because I am using another LEFT JOIN here, I have two columns namem "qguid"*/
LEFT OUTER JOIN ##Temp c on c.qguid = a.quoteguid2;
Another way,
declare #CurDate datetime=getdate()
Declare #CurDate1 varchar(8)
select #CurDate1= replace(convert(varchar(8), #CurDate, 112), ':','')
select #CurDate1
SET #cols = STUFF((SELECT ',' + QUOTENAME(c.locationCode) +#CurDate1
FROM Catalytic_vw_LocationCodeByLine c WHERE c.linename =#LineName order by c.CompanyName, c.LocationCode
FOR XML PATH('')),1,1,'')
If I am understanding your question correctly you need to use an existing stored procedure to get data for an SSRS report and you cannot modify the procedure. The problem is the stored procedure returns two columns with the same name and SSRS will not accept that in a dataset.
To get around that call the stored procedure and store its results in a temp table with different column names. Then output the temp table contents. This gives you fill control over the name of the columns. See example below.
CREATE PROCEDURE dbo.sp_Test
AS
BEGIN
SELECT
1 AS 'Test1',
2 AS 'Test2',
3 AS 'Test3',
3 AS 'Test3'
END
CREATE TABLE #Test
(
Test1 int,
Test2 int,
Test3 int,
Test4 int
)
INSERT INTO #Test
EXEC dbo.sp_Test
SELECT * FROM #Test
DROP TABLE #Test
I have a master table which contains the table names and columns corresponding to that table.
I want to write a procedure which iterates through all the records of tables and gets all the data and returns it as a single result set.
You need to use Dynamic Query
DECLARE #sql VARCHAR(max)=''
SET #sql = (SELECT #sql + 'select ' + column_name + ' from '
+ table_name + ' union all '
FROM master_table
FOR xml path(''))
SELECT #sql = LEFT(#sql, Len(#sql) - 9)
EXEC (#sql)
Note : The datatype of all the columns should be same. If it is not the case then you may have to do explicit conversion to varchar
SET #sql = (SELECT #sql + 'select cast(' + column_name + ' as varchar(4000)) from '
+ table_name
+ ' union all '
FROM Master_table
FOR xml path(''))
Assuming that all tables listed in your Master table is having same columns with same order and data types. Then it will be as follows:
create table ##a
(
Value int
)
create table ##b
(
Value int
)
create table ##c
(
Value int
)
declare #all table
(
Value int
)
declare #master table
(
TableName varchar(10)
)
declare #TableName varchar(10)
insert ##a values (1), (2), (3)
insert ##b values (4), (5), (6)
insert ##c values (7), (8), (9)
insert #master values ('##a'), ('##b'),('##c')
declare looper cursor local static forward_only read_only for
select TableName from #master
open looper
fetch next from looper into #TableName
while ##fetch_status = 0
begin
insert #all exec('select Value from ' + #TableName)
fetch next from looper into #TableName
end
close looper
deallocate looper
select * from #all
drop table ##a
drop table ##b
drop table ##c
If the tables are of different structures, please visit Stored procedures and multiple result sets in T-SQL. It will squeeze the content of each table into a single XML cell. The article also explains how to read them back.
I assume that you are using many tables with different columns in your master table. You should loop your master table. Try like this,
DECLARE #sql NVARCHAR(max) = ''
DECLARE #start INT = 1
,#end INT = 0
,#tablename VARCHAR(100) = ''
DECLARE #TableList TABLE (
id INT identity(1, 1)
,tablename VARCHAR(128)
)
INSERT INTO #TableList (tablename)
SELECT DISTINCT table_name
FROM YourMasterTableName
WHERE TABLE_NAME = 'productss'
SET #end = ##ROWCOUNT
WHILE (#start <= #end)
BEGIN
SET #tablename = (
SELECT tablename
FROM #TableList
WHERE id = #start
)
SET #sql = (
SELECT ',[' + column_name + ']'
FROM YourMasterTableName M
WHERE TABLE_NAME = #tablename
FOR XML path('')
)
SET #sql = 'SELECT ' + stuff(#sql, 1, 1, '') + ' FROM ' + #tablename
EXEC sp_executesql #sql
SET #start = #start + 1
END
I have a stored procedure that that currently works for pagination.
How I use the stored procedure is, I pass a dynamic WHERE clause from MS Access so that I can filter my data.
But when I filter the data the #MaxRowNum is still counting the number of records in the table rather than the number of records with the WHERE clause added.
Is it possible to count the number of records within the WHERE clause.
This is my code so far...
CREATE PROCEDURE [dbo].[SP_FINANCIALSWHERE]
#StartRow AS INT,
#EndRow INT,
#ORGCODE AS VARCHAR(6),
#strWHERE AS VARCHAR(256)
WITH RECOMPILE
AS
BEGIN
SET NOCOUNT ON;
--Declare variables
DECLARE #MaxRowNum INT
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N'SELECT #MaxRowNum = COUNT(*)
FROM dbo.Posting' + #ORGCODE + '
SELECT
x2.*
,#MaxRowNum as MaxRowNumber
FROM (
SELECT
x1.*
,ROW_NUMBER() OVER(ORDER BY PostingID ASC) AS RowNumber
FROM (
SELECT *
FROM dbo.Posting' + #ORGCODE + '
WHERE ' + #strWHERE + '
) AS x1
) AS x2
WHERE
RowNumber BETWEEN #STARTROW AND #ENDROW;';
EXEC sp_executesql #sql, N'#StartRow INT,#EndRow AS INT, #ORGCODE VARCHAR(6), #strWHERE VARCHAR (256), #MaxRowNum INT', #StartRow, #EndRow,#ORGCODE,#strWHERE, #MaxRowNum;
END
I am quite new to SQL so please explain in layman terms.
The first of the two SELECT queries inside your procedure is the issue, it seems. The first:
SET #SQL = N'SELECT #MaxRowNum = COUNT(*) FROM dbo.Posting' + #ORGCODE + '
is setting #MaxRowNum. The WHERE clause is not appended here, so you get the #MaxRowNum equals the count of the entire table. The simplest way to modify this code would be to change the above line to:
SET #SQL = N'SELECT #MaxRowNum = COUNT(*) FROM dbo.Posting' + #ORGCODE + ' WHERE ' + #strWHERE + '
This is the same code that comprises your derived table x1. This should give you the same count as the count in your inner query, as it is your inner query.
This solution is for an unbounded Gridview paging and having problem with the syntax of this query:
> #currTable varchar(20),
#startRowIndex int,
#maximumRows int,
#totalRows int OUTPUT
AS
DECLARE #first_id int, #startRow int
IF #startRowIndex = 1
SET #startRowIndex = 1
ELSE
SET #startRowIndex = ((#startRowIndex - 1) * #maximumRows)+1
SET ROWCOUNT #startRowIndex
DECLARE #sql varchar(250);
SET #sql = 'SELECT ID, StringID_from_Master, GUID, short_Text, lang_String, date_Changed, prev_LangString, needsTranslation, displayRecord, brief_Descrip FROM ' + #currTable + ' ';
EXECUTE(#sql);
PRINT #first_id
SET ROWCOUNT #maximumRows
SELECT #sql = 'SELECT ' + CAST(#first_id as varchar(20)) + ' = ID FROM ' + QUOTENAME(#currTable) + ' ORDER BY ID ' ;
EXEC (#sql);
SET ROWCOUNT 0
-- Get the total rows
SET #sql = 'SELECT ' + + CAST(#totalRowsas varchar(20)) + ' = COUNT(ID) FROM ' + #currTable + ' ';
EXECUTE(#sql);
RETURN
<
The errors is:
Conversion failed when converting the varchar value ''SELECT ' to data type int.
Tried also
nvarchar and varchar. = + CAST(#first_id as varchar(10)) +
If you're trying to implement paging, this is wrong in so many ways. First, you're using SET ROWCOUNT to limit to #startRowIndex, but then you're selecting ALL n rows (with no ORDER BY), then getting the first ID, then counting the total rows by selecting from the table? Might I suggest a better approach?
CREATE PROCEDURE dbo.PageSmarter
#Table NVARCHAR(128), -- table names should not be varchar(20)
#FirstRow INT,
#PageSize INT,
#TotalRows INT OUTPUT
AS
BEGIN
SET NOCOUNT ON; -- always, in every stored procedure
DECLARE
#first_id INT,
#startRow INT,
#sql NVARCHAR(MAX);
SET #sql = N'WITH x AS
(
SELECT
ID,
rn = ROW_NUMBER() OVER (ORDER BY ID)
FROM
' + #Table + '
)
SELECT rn, ID
INTO #x FROM x
WHERE rn BETWEEN ' + CONVERT(VARCHAR(12), #FirstRow)
+ 'AND (' + CONVERT(VARCHAR(12), #FirstRow)
+ ' + ' + CONVERT(VARCHAR(12), #PageSize) + ' - 1);
SELECT first_id = MIN(ID) FROM #x;
SELECT
ID, StringID_from_Master, GUID, short_Text, lang_String, date_Changed,
prev_LangString, needsTranslation, displayRecord, brief_Descrip
FROM ' + #Table + ' AS src
WHERE EXISTS
(
SELECT 1 FROM #x
WHERE ID = src.ID
);';
EXEC sp_executeSQL #sql;
SELECT #totalRows = SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE [object_id] = OBJECT_ID(#Table);
END
GO
DECLARE #tr INT;
EXEC dbo.PageSmarter 'dbo.tablename', 10, 2, #tr OUTPUT;
SELECT #tr;
I haven't tested all edge cases with this specific implementation. I will confess, there are much better ways to do this, but they usually aren't complicated with the additional requirement of dynamic table names. This suggests that there is something inherently wrong with your design if you can run the exact same queries against any number of tables and get similar results.
In any case, you can review some of the (quite lengthy) discussion about various approaches to paging over at SQL Server Central:
http://www.sqlservercentral.com/articles/T-SQL/66030/
There are 62 comments following up on the article:
http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx
I am guessing your #first_id field is an int. If so, then you need to CAST/Convert your #first_id value to a string/varchar.
CAST(#first_id as varchar(10))
or
Convert(varchar(10), #first_id)
MSDN documentation on CAST/Convert for SQL server
EDIT: After looking at your query again, I notice that you are setting your #first_id = ID, This is incorrect syntax, the correct syntax would be below.
SELECT #sql = 'SELECT ID AS ' + CAST(#first_id as varchar(10)) + ' FROM ' +
QUOTENAME(#currTable) + ' ORDER BY ID ' ;
EXEC (#sql);
It appears you're trying to create an alias for your column ID. The string you're building won't result in a valid SQL statement if it contains a number. It would come out to something like this:
SELECT 123 = ID FROM dbo.MyTable ORDER BY ID
Try this:
SELECT ID AS '123' FROM dbo.MyTable ORDER BY ID
To achieve that:
SELECT #sql = 'SELECT ID AS ''' + CAST(#first_id as varchar(10)) +
''' FROM ' + QUOTENAME(#currTable) +
' ORDER BY ID ' ;
I would do it this way
create table #e (a int)
SET #sql = 'insert #e SELECT COUNT(ID) FROM ' + #currTable + ' ';
exec(#sql)
select #totalRows = a from #e
drop table #e