Snowflake passing parameters - snowflake-cloud-data-platform

I have a function with parameters. If I pass null as the parameter in a where clause it brings back all results eg
RETURNS TABLE (CUSTOMER_CODE VARCHAR, CUSTOMERNAME VARCHAR)
LANGUAGE SQL
AS '
SELECT CUSTOMER_CODE, CUSTOMERNAME FROM DIM_CUSTOMER
WHERE CUSTCODE IS NULL OR CUSTOMER_CODE = CUSTCODE
'
I would like to change the SQL to if the parameter CUSTCODE = 'ALL' then pass NULL value and bring back all results else CUSTOMER_CODE = CUSTCODE
Thank you in advance!
Leon

Use a CASE statement.
Example -
create or replace function test_fun (CUSTOMER_CODE number, CUSTOMERNAME VARCHAR)
RETURNS TABLE (CUSTOMER_CODE number, CUSTOMERNAME VARCHAR)
AS 'SELECT C_CUSTKEY, C_NAME FROM customer WHERE C_CUSTKEY=
(case when customer_code=1 then NULL else CUSTOMER_CODE end)';

Try the below method:
create or replace table customer (
CUSTOMER_CODE int,
CUSTOMERNAME varchar
);
insert into customer values (1, 'customer 1'), (2, 'customer 2');
create or replace function test_fun (CODE varchar)
RETURNS TABLE (CUSTOMER_CODE number, CUSTOMERNAME VARCHAR)
AS
$$
SELECT
CUSTOMER_CODE,
CUSTOMERNAME
FROM customer
WHERE
true = (
case
when UPPER(CODE) = 'ALL' then true
else false
end
)
OR
CUSTOMER_CODE= CODE
$$;
Result:
select * from table(test_fun('1'));
+---------------+--------------+
| CUSTOMER_CODE | CUSTOMERNAME |
|---------------+--------------|
| 1 | customer 1 |
+---------------+--------------+
select * from table(test_fun('2'));
+---------------+--------------+
| CUSTOMER_CODE | CUSTOMERNAME |
|---------------+--------------|
| 2 | customer 2 |
+---------------+--------------+
select * from table(test_fun('3'));
+---------------+--------------+
| CUSTOMER_CODE | CUSTOMERNAME |
|---------------+--------------|
+---------------+--------------+
select * from table(test_fun('all'));
+---------------+--------------+
| CUSTOMER_CODE | CUSTOMERNAME |
|---------------+--------------|
| 1 | customer 1 |
| 2 | customer 2 |
+---------------+--------------+

Related

How to append metadata to a grouped selection by primary key

I have a list of favorites like:
Sample Data
| key | item_id | list_name | customer_id |meta |
|-----|---------|-----------|--------------|---------------|
| 1 | A-11 | aa11 | 001 | unique-data-1 |
| 2 | A-11 | bb22 | 001 | unique-data-2 |
| 3 | A-26 | cc33 | 001 | unique-data-3 |
| 4 | A-28 | aa11 | 002 | unique-data-4 |
| 5 | J-52 | aa11 | 001 | unique-data-5 |
| 6 | X-53 | aa11 | 001 | unique-data-6 |
Desired Output
for #item_id nvarchar(20) = 'A-11'
| key | isFavorited | list_name | meta |
|-----|-------------|-----------|---------------|
| 1 | Y | aa11 | unique-data-1 |
| 2 | Y | bb22 | unique-data-2 |
| 3 | N | cc33 | unique-data-3 |
And would like to return a selection of all available lists, as well as whether or not a particular item is part of that list, with its meta data.
declare #item_id nvarchar(20) = 'A-11'
declare #customer_id nvarchar(20) = 001
select
[key],
[isFavorited] = max(case when [item_id] = #item_id then 'Y' else 'N' end)
[list_name]
[meta]
from favorites
where customer_id = #customer_id
group by [list_name], [key], [meta]
Issues when trying various methods:
The issue I'm having is that since the meta is unique the group by destroys the uniqueness of the select
A cross apply like the following doesn't apply the correct meta based on a matching key.
cross apply (
select top 1
[meta]
from favorites
where customer_id = #customer_id
)
When selecting by row number, the actual key to join back to is lost, so I'm unable to join the meta.
"noRow" = row_number() over(order by h_po_no asc)
I'd like to
Pass in an item_id and customer_id
Return all lists for that customer
Get favorite status for each list of passed in item_id
An item is flagged favorite if it matches both list_name and item_id for a given customer_id
Get row primary key and meta data
How can I return a distinct selection of list_name, isFavorite status, key, and it's meta?
To return the desired output you don't need any aggregation at all. A simple case expression and a where clause will accomplish this.
declare #Favorites table
(
MyKey int
, item_id varchar(10)
, list_name varchar(10)
, customer_id varchar(10)
, meta varchar(20)
)
insert #Favorites values
(1, 'A-1', 'list-1', '001', 'unique-data-1')
, (2, 'A-1', 'list-2', '001', 'unique-data-2')
, (3, 'A-2', 'list-3', '001', 'unique-data-3')
, (4, 'A-2', 'list-1', '002', 'unique-data-1')
select *
from #Favorites
declare #item_id nvarchar(20) = 'A-1'
, #customer_id nvarchar(20) = '001'
select f.MyKey
, isFavorited = case when f.item_id = #item_id then 'Y' else 'N' end
, listName = f.list_name
, f.meta
from favorites f
where f.customer_id = #customer_id
order by f.MyKey
Test Parameters
declare #item_id nvarchar(20) = 'A-11'
declare #customer_id nvarchar(20) = 001
Solution
drop table if exists #tmp
;with cte as (
select
[key],
[list_name],
[rn] = row_number() over (partition by list_name order by list_name desc)
from favorites
where customer_id = #customer_id
group by [list_name], [key], [meta]
)
select *
into #tmp
from cte
where [rn] = 1
select
[i],
[json],
#t.[tmp]
from #tmp #t
inner join (
select
[isFavorited] = max(case when [item_id] = #item_id then 'Y' else 'N' end)
[list_name]
from favorites
where customer_id = #customer_id
group by [list_name]
) j
on j.list_name = #t.list_name

SQL Server - transpose table and return temporary table with correct format

I have a non-modifiable SQL transaction that returns the following data:
----------------------
| NAME | VALUE |
----------------------
| Amount | ... |
----------------------
| Target | ... |
----------------------
| Date | ... |
----------------------
| Amount | ... |
----------------------
| Target | ... |
----------------------
| Date | ... |
----------------------
e.g:
I want to format it so it looks like:
-----------------------------------------
| Amount | Target | Date |
-----------------------------------------
| ... | ... | ... |
-----------------------------------------
How would I go on accomplishing this?
The code I have is:
SELECT
NAME, VALUE
FROM
function(#data)
/* AS PIVOT TABLE(...)*/
And I want to return a temporary table with the correct format.
Try this just use the select and replace #foo with your source of records, and ignore all of the setup unless you just want to run this specific example.
The grouping is based on position, and you can use floor((row_number() over (order by (select 1)) - 1) / 3) to get a group for every three rows.
create table #foo (
Name varchar(50),
StringValue varchar(50))
insert into #foo values ('Amount', '200')
insert into #foo values ('Target', '66')
insert into #foo values ('Date', '2017-1-1')
insert into #foo values ('Amount', '205')
insert into #foo values ('Target', '67')
insert into #foo values ('Date', '2017-3-1')
select
max(case when Name = 'Amount' then StringValue else null end) as Amount,
max(case when Name = 'Target' then StringValue else null end) as Target,
max(case when Name = 'Date' then StringValue else null end) as Date
from (
select floor((row_number() over (order by (select 1)) - 1) / 3) as group_on, * from #foo
) temp
group by group_on
drop table #foo

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 |
+----------------+--------------+---------------------+----------------+-----------+----------------------------------+

Creating a column in runtime

I have a Query
select Distinct EmailAddress as MailId from tblUsers
it shows the emails, but i want to create a column through the query which will show total number of emails.
Please help me
SELECT *, COUNT(1) OVER ()
FROM (
SELECT DISTINCT EmailAddress
FROM tblUsers
) t
Just for R&D -
CREATE FUNCTION dbo.udf_GetCount ()
RETURNS INT
WITH SCHEMABINDING
AS BEGIN
RETURN (SELECT COUNT(DISTINCT EmailAddress) FROM tblUsers)
END
GO
ALTER TABLE dbo.tblUsers
ADD TotalCnt AS dbo.udf_GetCount() PERSISTED
GO
or
SELECT DISTINCT EmailAddress, t.TotalCnt
FROM tblUsers
CROSS JOIN (
SELECT TotalCnt = COUNT(DISTINCT EmailAddress)
FROM tblUsers
) t
Query
CREATE TABLE #email
(
email VARCHAR(MAX)
);
INSERT INTO #email VALUES
('a.c#s'),
('a.c#s'),
('b.c#s'),
('b.c#s'),
('c.c#s'),
('c.c#s'),
('d.c#s');
If you want count of each email, then
SELECT email, COUNT(email) AS [Count]
FROM #email
GROUP BY email;
Result
+-------+-------+
| email | Count |
+-------+-------+
| a.c#s | 2 |
| b.c#s | 2 |
| c.c#s | 2 |
| d.c#s | 1 |
+-------+-------+
else count of total distinct email
SELECT DISTINCT email, (SELECT COUNT(DISTINCT email) FROM #email) AS [Count]
FROM #email;
Result
+-------+-------+
| email | Count |
+-------+-------+
| a.c#s | 4 |
| b.c#s | 4 |
| c.c#s | 4 |
| d.c#s | 4 |
+-------+-------+
SQL Fiddle demo

Need help pivoting some data

I'm hoping someone can help me. I'm trying to pivot some data on SQL Server 2005 and can't quite get the results I'm looking for.
This is my current table schema:
| ProductCode | AttributeName | AttributeValue |
| 1 | AttributeA | 10 |
| 1 | AttributeB | 20 |
| 2 | AttributeA | 30 |
| 2 | AttributeB | 40 |
| 3 | AttributeA | 50 |
This is the results I'm trying to achieve:
| ProductCode | AttributeA | AttributeB |
| 1 | 10 | 20 |
| 2 | 30 | 40 |
| 3 | 50 | NULL |
I know that I can achieve this result with the following SQL:
SELECT DISTINCT ProductCode,
(SELECT AttributeValue
FROM attributes
WHERE ProductName = 'AttributeA' AND ProductCode=a.ProductCode) AttributeA,
(SELECT AttributeValue
FROM attributes
WHERE ProductName = 'AttributeB' AND ProductCode=a.ProductCode) AttributeB,
FROM attributes a
Although that SQL does produce the result I'm looking for, it's obviously not dynamic (in reality, I not only have more Attribute Types, but different products have different sets of attributes) and it also scans the table 3 times. It's also a maintenance nightmare.
I tried using the PIVOT functionality of SQL Server, but with no luck.
Can anyone help?
create table #attributes (ProductCode int,
AttributeName varchar(20),
AttributeValue int)
insert into #attributes values (1, 'AttributeA', 10)
insert into #attributes values (1, 'AttributeB', 20)
insert into #attributes values (2, 'AttributeA', 30)
insert into #attributes values (2, 'AttributeB', 40)
insert into #attributes values (3, 'AttributeA', 50)
declare #attributes_columns nvarchar(max)
set #attributes_columns
= (
select ', [' + AttributeName + ']'
from
(
select distinct AttributeName as AttributeName
from #attributes
) t
order by t.AttributeName
for xml path('')
)
set #attributes_columns = stuff(#attributes_columns,1,2,'')
declare #sql nvarchar(max)
set #sql = N'
select ProductCode, <attributes_columns>
from
(select ProductCode, AttributeName, AttributeValue
from #attributes )p
pivot
(
sum(AttributeValue) for AttributeName in (<attributes_columns>)
) as pvt
'
set #sql = replace(#sql, '<attributes_columns>', #attributes_columns)
print #sql
exec sp_executesql #sql
drop table #attributes

Resources