How to use subquery in openquery where clause - sql-server

So I have this Openquery in a stored procedure, where I need to return results where the values in a column are the same as the ones in a local table
exec spx_SELECT_LocalizacoesEtiquetas
GO
IF OBJECT_ID('dbo.spx_SELECT_LocalizacoesEtiquetas') IS NOT NULL
DROP PROCEDURE spx_SELECT_LocalizacoesEtiquetas
GO
CREATE PROCEDURE spx_SELECT_LocalizacoesEtiquetas
AS
BEGIN
SET NOCOUNT ON
DECLARE #SQL NVARCHAR(MAX);
SET #SQL =
'SELECT ET0109 AS Localizacao, Etiquetas
FROM OpenQuery(MACPAC, ''SELECT FET001.ET0109, FET001.ET0101 AS Etiquetas
FROM AUTO.D805DATPOR.FET001 FET001
WHERE FET001.ET0104=''''POE'''' AND FET001.ET0105=''''DIS'''''' AND FET001.ET0101 = '''''
+ (SELECT Localizacao FROM xLocalizacao WHERE InventarioID = 1 ) + ''''' ) ';
EXEC sp_executesql #SQL
END
basically it won't accept the subquery 'cause it says it has too many values.... So my question is. How can i limit the values from the subquery where the values of a column match the ones in a local table? basically a where column A in open query = column B in local table
EDIT.
Here is what I'm trying to achieve.
SubQuery returns from Local table
Column A
| A |
| B |
| C |
| D |
| E |
Open query returns
Column A Column B
| A | 0 |
| A | 0 |
| A1 | 1 |
| A | 2 |
| B | 3 |
| B | 3 |
| B1 | 4 |
Final result should Be
Final query
Column A Column B
| A | 0 |
| A | 0 |
| A | 2 |
| B | 3 |
| B | 3 |

Ok, there are two changes you need to make in your approach.
First of all, you are concatenating your sub-query to a string. No matter what, your subquery has to return a single value, not a multi-row set. So you need to use the method of your choice for having your query return a comma-separated string.
Here's one that will work on any version of SQL Server after 2005.
in other words, instead of this:
Column A
| A |
| B |
| C |
| D |
| E |
your subquery needs to return a single varchar column containing this:
'A','B','C','D','E'
The next change you need to make is using IN instead of =.
So instead of this:
AND FET001.ET0101 = '''''
+ (Your Subquery) + ''''' ) '
you need this:
AND FET001.ET0101 IN ( '
+ (Your Subquery) + ') ) '

Related

How can to get distinct data of all the columns in a table in spearte result set in SQL

I have created a Stored Procedure to get distinct data of all the columns. But I have to Specify each column name of the respective table.
Bur I don't want to specify each column name of the table and get the distinct data of all the columnn in separte result set.
+----+------+---------+-----------+
| Id | name | Address | City |
+----+------+---------+-----------+
| 1 | A | Max | Rajasthan |
| 2 | A | Min | Delhi |
| 1 | A | Max | Rajathan |
| 1 | A | Min | UP |
+----+------+---------+-----------+
This is the code of my Stored Procedure for getting different result set of each column
create proc sp_task1 #table varchar(20)
as
begin
exec('
select distinct id FROM ' +#table+'
')
exec('
select distinct name FROM ' +#table+'
')
exec('
select distinct address FROM ' +#table+'
')
exec('
select distinct city FROM ' +#table+'
')
end
exec sp_task1 #table = 'table1'
This is what I get in result when I Execute the SP.
+----+
| id |
+----+
| 1 |
| 2 |
+----+
+------+
| name |
+------+
| A |
+------+
+---------+
| Address |
+---------+
| Max |
| Min |
+---------+
+-----------+
| city |
+-----------+
| Rajasthan |
| Delhi |
+-----------+
Now, I want to do this dynamically without specifying the column names.
Please give me any kind of help regarding this issue.
You can use below query to do this.
TEST SETUP
CREATE TABLE Test(id int, name varchar(20), city varchar(20));
INSERT INTO Test
values(1,'abc','chennai'),
(2,'abc','bangalore');
CREATE PROCEDURE USP_GetDistinct(#TableName SYSNAME,#TableSchema SYSNAME )
AS
BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = (
SELECT 'SELECT DISTINCT ' +
Column_Name +
' FROM ' + QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(Table_Name) + CHAR(13)+ CHAR(10) + 'GO'+CHAR(13)+ CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE TABLE_NAME = #TableName AND table_schema = #TableSchema
FOR XML PATH(''), Type
).value('.', 'varchar(max)')
--PRINT #SQL
EXECUTE (#SQL)
END
Execute procedure
EXEC USP_GetDistinct #TableName='Test', #TableSchema='dbo'
Result set
+----+
| id |
+----+
| 1 |
| 2 |
+----+
+------+
| name |
+------+
| abc |
+------+
+-----------+
| city |
+-----------+
| bangalore |
| chennai |
+-----------+

Pivoting rows to columns depending on data from another table

I have two tables VisitorsPerDay and Languages as follows:
Languages table
| Code | Alias |
|---------------------|------------------|
| EN | English |
| AR | Arabic |
| FR | French |
| JP | Japanese |
VisitorsPerDay table
| Date | VisitorLanguage | Count |
|---------------------|------------------|-------------|
| 10/1/2019 | EN | 20 |
| 10/1/2019 | EN | 10 |
| 10/1/2019 | AR | 5 |
| 15/1/2019 | FR | 1 |
What the result should be is aggregated data for each day and two columns for each language in the languages table dynamically in which if a new language has been added there will be no need to edit the stored procedure
| Date | TotalVisits | En Visits | En AVG Visit % |
|---------------------|------------------|-------------|------------------|
| 10/1/2019 | 35 | 30 | 85% |
| 15/1/2019 | 1 | 0 | 0% |
What I have done is created a dynamic query and a cursor that loop over the languages and generate the require SQL statements for each language and append it to the dynamic query
What I want to know is there a better way to get the result set or is a dynamic query OK?
You have to use Dynamic SQL, the query will be ugly and not easy to maintain
declare #sql nvarchar(max)
select #sql = isnull(#sql + ',', 'SELECT [Date], TotalVisits = sum([Count]),' + char(13))
+ 'SUM(CASE WHEN VisitorLanguage = ''' + Code + ''' THEN [Count] END) AS [' + Code + ' Visits],'+ char(13)
+ 'SUM(CASE WHEN VisitorLanguage = ''' + Code + ''' THEN [Count] END) * 100 / SUM([Count]) AS [' + Code + ' AVG Visits %]'+ char(13)
from Languages
select #sql = #sql + 'FROM VisitorsPerDay GROUP BY [Date]'
-- print out the dynmamic query
print #sql
exec sp_executesql #sql

Dynamic Sql Pivot Two Columns of Table

Using Dynamic Pivots Tables, I'm trying to get this table: http://www.sqlfiddle.com/#!18/9f1cf/47
To look something like this: (Some Columns removed for brevity, assume I can have one or more columns past "Chosen Council", this is the expected design only not the expected result)
Note that Zip codes can be null, can share Councils, and can repeat over the days
+============+=======+================+============================+====================================+=========================+=====================+
| Call Date | Zip | Chosen Council | Early Childhood Group Care | Development / Developmental Delays | Caregiver Mental Health | Behavioral Concerns |
+============+=======+================+============================+====================================+=========================+=====================+
| 2018-05-01 | 85000 | Maricopa North | null | 1 | 2 | null |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-01 | 85001 | Maricopa North | 1 | null | null | null |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-01 | null | null | null | 2 | null | null |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-02 | 85000 | Maricopa North | null | 1 | 1 | 3 |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-02 | 85003 | Phoenix South | null | null | null | 2 |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-02 | 85004 | Phoenix South | 1 | 2 | null | 2 |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
| 2018-05-02 | null | null | null | 1 | 1 | null |
+------------+-------+----------------+----------------------------+------------------------------------+-------------------------+---------------------+
I've seen a number of questions regarding Pivot Tables, both hard coded and dynamic, and I'm still not grasping it.
Here, I was able to get a Dynamic Pivot Table for just the Call Topic Names and their Counts: http://www.sqlfiddle.com/#!18/9f1cf/39
But that is only a single row for everything, it also seems to be ignoring nulls.
Here I tried to expand on the above, and while it seems to be spacing out better, I haven't figured out how to attach my Call Date, Zip, or Chosen Council columns: http://www.sqlfiddle.com/#!18/9f1cf/37
Any ideas how I can do this?
ASCII Table made with: Made with https://ozh.github.io/ascii-tables/
Maybe you need something like below
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', _callTopics.' + QUOTENAME(Name)
FROM
(
SELECT
_callTopics.Name
FROM CallTopics AS _callTopics
INNER JOIN CallTopicsPerRegion AS _callTopicsPerRegion
ON _callTopics.Name = _callTopicsPerRegion.CallTopicName
GROUP BY _callTopics.Name
) AS x;
SET #sql = N'
SELECT CallDate
,Zip
,ChosenCouncil, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT _callTopics.Name, _callTopicsPerRegion.CallTopicCount,
CallDate
,Zip
,ChosenCouncil
FROM CallTopics AS _callTopics
INNER JOIN CallTopicsPerRegion AS _callTopicsPerRegion
ON _callTopics.Name = _callTopicsPerRegion.CallTopicName
) AS j
PIVOT
(
SUM(CallTopicCount) FOR Name IN ('
+ STUFF(REPLACE(#columns, ', _callTopics.[', ',['), 1, 1, '')
+ ')
) AS _callTopics order by 1,2 ,3';
--PRINT #sql;
EXEC sp_executesql #sql;
Here's fiddle link

Scalar function occurring request timeout issue in SQL Server while using in stored procedure

This is salar fuction . I am using this in Stored procedure with muliple parameters. For small results it is good but for big data it gets time out and also taking a long execuition time. Please share some other alternate or some enhancements
ALTER FUNCTION [dbo].[FNGETMULIPLEASSIGNESS_NEW2]
(
#TIMELINEID INT,
#MILSTONEID INT,
#TASKID INT
)
RETURNS varchar(max)
AS
BEGIN
DECLARE #Assignees varchar(max)='', #isExists bit=0
if(#TASKID=0)
BEGIN
Select #Assignees = #Assignees+ FIRSTNAME +' ' + LASTNAME+', '
FROM CASETIMELINEPEOPLE
INNER JOIN USERDETAIL ON
CASETIMELINEPEOPLE.PEOPLEUSERID=USERDETAIL.USERID
WHERE (CASETIMELINEID= #TIMELINEID) AND
(TEMPLATEMILESTONEID=#MILSTONEID) AND
(TEMPLATETASKID is null) and CASETIMELINEPEOPLE.isdeleted=0
END
else
BEGIN
Select #Assignees = #Assignees+ FIRSTNAME +' ' + LASTNAME+','
FROM CASETIMELINEPEOPLE
INNER JOIN USERDETAIL ON
CASETIMELINEPEOPLE.PEOPLEUSERID=USERDETAIL.USERID
WHERE (CASETIMELINEID= #TIMELINEID) AND
(TEMPLATEMILESTONEID=#MILSTONEID) AND
(TEMPLATETASKID=#TASKID) and CASETIMELINEPEOPLE.isdeleted=0
END
SELECT #Assignees=SUBSTRING(#Assignees, 0,LEN(#Assignees))
RETURN #Assignees
END
Using an inline table valued function will improve performance.
Reference:
When is a SQL function not a function? "If it’s not inline, it’s rubbish." - Rob Farley
Inline Scalar Functions - Itzik Ben-Gan
Scalar functions, inlining, and performance: An entertaining title for a boring post - Adam Machanic
TSQL User-Defined Functions: Ten Questions You Were Too Shy To Ask - Robert Sheldon
Here is an inline table valued function version of your scalar function that uses the stuff() with select ... for xml path ('') method of string concatenation.:
create function dbo.fn_get_multiple_assigness_itvf (
#timelineid int
, #milstoneid int
, #taskid int
) returns table as return (
select Assignees = stuff((
select ',' + firstname + ' ' + lastname
from casetimelinepeople ctp
inner join userdetail ud
on ctp.peopleuserid=ud.userid
where casetimelineid = #timelineid
and templatemilestoneid = #milstoneid
and (templatetaskid = #taskid
or (#taskid = 0 and templatetaskid is null)
)
and ctp.isdeleted=0
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'')
)
go
rextester demo: http://rextester.com/UZTJS46485
test setup:
create table casetimelinepeople (
casetimelineid int
, peopleuserid int
, templatemilestoneid int
, templatetaskid int
, isdeleted bit not null default 0
);
insert into casetimelinepeople values
(1,1,1,null,0)
,(1,2,1,null,0)
,(1,3,1,null,0)
,(1,2,1,1,0)
,(1,3,1,1,0)
create table userdetail (
userid int not null
, firstname varchar(32) not null
, lastname varchar(32) not null);
insert into userdetail values
(1, 'Some', 'One')
,(2, 'Avinash', 'Raikwar')
,(3, 'Sql','Zim');
go
And querying the inline table valued function like so:
select *
from dbo.fn_get_multiple_assigness_itvf(1,1,0)
returns
+----------------------------------+
| Assignees |
+----------------------------------+
| Some One,Avinash Raikwar,Sql Zim |
+----------------------------------+
select *
from dbo.fn_get_multiple_assigness_itvf(1,1,1)
returns:
+-------------------------+
| Assignees |
+-------------------------+
| Avinash Raikwar,Sql Zim |
+-------------------------+
Using cross apply() to call the function for each row in a query:
select *
from casetimelinepeople ctp
cross apply dbo.fn_get_multiple_assigness_itvf(
ctp.casetimelineid
, ctp.templatemilestoneid
, ctp.templatetaskid
) x
returns:
+----------------+--------------+---------------------+----------------+-----------+----------------------------------+
| casetimelineid | peopleuserid | templatemilestoneid | templatetaskid | isdeleted | Assignees |
+----------------+--------------+---------------------+----------------+-----------+----------------------------------+
| 1 | 1 | 1 | NULL | False | Some One,Avinash Raikwar,Sql Zim |
| 1 | 2 | 1 | NULL | False | Some One,Avinash Raikwar,Sql Zim |
| 1 | 3 | 1 | NULL | False | Some One,Avinash Raikwar,Sql Zim |
| 1 | 2 | 1 | 1 | False | Avinash Raikwar,Sql Zim |
| 1 | 3 | 1 | 1 | False | Avinash Raikwar,Sql Zim |
+----------------+--------------+---------------------+----------------+-----------+----------------------------------+

Retrieving CSV values in a single row as multiple rows in Sql Server 2008

I have a table in my database as follows:
+-------+
| Name |
+-------+
| A |
| B |
| C,D |
| A,B,E |
+-------+
I want the output as
+------+
| Name |
+------+
| A |
| B |
| C |
| D |
| E |
+------+
My question is how to retrieve C,D and A,B,E into different rows?
First create a custom split() function.
Split Function
CREATE FUNCTION dbo.Split(#String nvarchar(4000), #Delimiter char(1))
RETURNS #Results TABLE (colA nvarchar(4000))
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
SELECT #INDEX = 1
WHILE #INDEX !=0
BEGIN
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
INSERT INTO #Results(colA) VALUES(#SLICE)
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
Table
CREATE TABLE names(name VARCHAR(MAX));
INSERT INTO names VALUES('A');
INSERT INTO names VALUES('B');
INSERT INTO names VALUES('C,D');
INSERT INTO names VALUES('A,B,E');
SELECT * FROM names;
Table Structure
+-------+
| name |
+-------+
| A |
| B |
| C,D |
| A,B,E |
+-------+
Then assign all the values as comma separated to a variable.
DECLARE #str VARCHAR(MAX)
SELECT #str=t.csv FROM (SELECT SUBSTRING(
(SELECT ',' + n.name
FROM names n
ORDER BY n.name
FOR XML PATH('')),2,200000) AS csv)t;
SELECT DISTINCT colA AS Name FROM Split(#str,',');
Result
+------+
| Name |
+------+
| A |
| B |
| C |
| D |
| E |
+------+
Fiddle Demo Here
Hope this will help you out.

Resources