T-Sql help needed in Sql Server 2005 - asp.net

I have created one stored procedure which runs on 5000 users in tbluser table with some filter condition in database.There are 4 filtering condition(FC1,FC2,FC3,FC4).Filtering condition has some ListBox and dropdown list of department and countries.I want output as given below:
ID Name StaffNo department Points
1 KK 111 dep1 2
2 NN 222 dep2 1
3 DD 333 dep3 4
I got ID,Name,StaffNo,department in resultset but not points.
points calculation would be based on filtering condition like
if FC1 matched user gained point 1,if both FC1 and FC2 matched user gained 2 point,if both FC1 ,FC2 and FC3 matched user gained 3 point etc.
--in stored procedure i m using dynamic query
DECLARE #SQL VARCHAR(2000)
SET #SQL = 'SELECT U.UserID, U.StaffNo,U.FirstName+'' ''+ U.LastName AS EmployeeName,''?'' AS Points FROM tblUser U '
SET #SQL = #SQL+' WHERE U.Department in (' + #SqlDepartment + ') '
---------------------Update---------------------------------------
IF #SqlLanguage <> ''
SET #SQL = #SQL+' OR U.UserID IN (SELECT UserID FROM Country WHERE LCValues IN ('+ #SqlLanguage +') )'
IF #SqlAreas <> ''
SET #SQL = #SQL+' OR U.UserID IN (SELECT UserID FROM tblAreas WHERE '+#SqlAreas+')'
---------------------Update---------------------------------------
...other filtering condition
EXEC (#SQL)
all filtering condition are implemented with OR logic.

Have you tried implementing a CASE statement to calculate the "Points"?
--in stored procedure i m using dynamic query
DECLARE #SQL VARCHAR(2000)
SET #SQL = '
SELECT
U.[UserID],
U.[StaffNo],
U.[FirstName]+'' ''+ U.[LastName] AS EmployeeName,
(
CASE WHEN EXISTS(SELECT 1 FROM [Country] WHERE /*Your filter comes in here*/) THEN 1 ELSE 0 END +
CASE WHEN EXISTS(SELECT 1 FROM [tblAreas] WHERE /*Your filter comes in here*/) THEN 1 ELSE 0 END +
CASE WHEN EXISTS(SELECT 1 FROM [OtherTable1] WHERE /*Your filter comes in here*/) THEN 1 ELSE 0 END +
CASE WHEN EXISTS(SELECT 1 FROM [OtherTable2] WHERE /*Your filter comes in here*/) THEN 1 ELSE 0 END
) AS Points
FROM [tblUser] U'
SET #SQL = #SQL+' WHERE U.Department in (' + #SqlDepartment + ') OR'...
...other filtering condition
EXEC (#SQL)

I think you might be better off working out the points in your code rather than in the SQL
The only way I can think of doing it is with UNIONS which would be horrible

You can use left outer join to your filter condition, group by UserID to not get duplicates, add a value of 1 for hits and use coalesce to set 0 for no hits.
Some sample code that shows what I mean using Area and Country as filter condition.
declare #U table (UserID int, Name varchar(50), StaffNo char(3), department char(4))
declare #C table (CountryID int, UserID int)
declare #A table (AreaID int, UserID int)
insert into #U values (1, 'KK', '111', 'dep1')
insert into #U values (2, 'NN', '222', 'dep2')
insert into #U values (3, 'DD', '333', 'dep3')
insert into #C values(1, 1)
insert into #C values(2, 1)
insert into #C values(3, 2)
insert into #C values(3, 3)
insert into #A values(1, 1)
insert into #A values(2, 1)
insert into #A values(3, 2)
select
U.UserID,
U.Name,
U.StaffNo,
U.department,
coalesce(C.Point, 0)+coalesce(A.Point,0) as Points
from #U as U
left outer join
(select UserID, 1 as Point
from #C
-- where ...?
group by UserID) as C
on U.UserID = C.UserID
left outer join
(select UserID, 1 as Point
from #A
-- where ...?
group by UserID) as A
on U.UserID = A.UserID

Related

join the values of two strings in a single loop

I have below Two Strings
Src Id = 1:2:3:4
Src Qty = 2:4:7:9
So I want to Insert into a Table like
Insert into tbl (Src_id,qty) values (1,2);
Insert into tbl (Src_id,qty) values (2,4);
Insert into tbl (Src_id,qty) values (3,7);
and so on for all
So How i can use a loop by using APEX_UTIL.STRING_TO_TABLE or something else to align the Src id and Qty to insert them as single row in a table
You don't need a loop (i.e. PL/SQL); everything can be done in SQL. Here's how:
SQL> with test (src_id, src_qty) as
2 (select '1:2:3:4', '2:4:7:9' from dual)
3 select regexp_substr(src_id, '[^:]+', 1, level) ||','||
4 regexp_substr(src_qty, '[^:]+', 1, level) result
5 from test
6 connect by level <= regexp_count(src_id, ':') + 1;
RESULT
---------------------------------------------------------
1,2
2,4
3,7
4,9
SQL>
I have done the Solution as below
DECLARE
l_src_arr2 APEX_APPLICATION_GLOBAL.VC_ARR2;
l_qty_arr2 APEX_APPLICATION_GLOBAL.VC_ARR2;
BEGIN
l_src_arr2 := APEX_UTIL.STRING_TO_TABLE ('1:2:3:4');
l_qty_arr2 := APEX_UTIL.STRING_TO_TABLE ('2:4:7:9');
FOR i IN 1 .. l_src_arr2.COUNT LOOP
DBMS_OUTPUT.PUT_LINE ('Src = ' || l_src_arr2 (i) || ' qty = ' || l_qty_arr2 (i));
END LOOP;
END;

Case statement duplicating rows - teradata

i have the following query and the problem is in the Case statement. It s being used in a Join condition. for some reason is bringing up both alternatives from the case
here s the code
SELECT C.GREGORIAN_MONTH_ID
,C.BUSINESS_PARTY_ID
,C.TOTAL_MONTO
,C.Capitas_Puntuales
,C.CUIT
,nb_apellido
,nb_oficial_actual
,nb_cne_obe
,nb_nodo
,nb_territorio
,cd_area_negocio
FROM (SELECT gregorian_month_id
,business_party_id
,Case when BUSINESS_PARTY_ID in (88888,200) then '9999999999999' else business_party_ident_num end CUIT
,SUM(amt_accum) Total_Monto
,count(*) Capitas_Puntuales
FROM dbsreg.A127932_PARTY_MAIN_PAYROLL_HISTORY
where gregorian_month_id= 201806
group by 1,2,3
) C
LEFT JOIN
(select NU_CUIT, nb_apellido,nb_oficial_actual, nb_cne_obe, nb_nodo, nb_territorio,cd_area_negocio
,(fh_corte/100 + 190000) gregorian_month_id
from dbsreg.a119527_base_info_gerencial
) G
on C.CUIT = G.NU_CUIT
and (case
when C.gregorian_month_id in (G.gregorian_month_id) then C.gregorian_month_id
else C.gregorian_month_id -1
END) = G.gregorian_month_id
ORDER BY C.BUSINESS_PARTY_ID
anyone can tell what s going on there?
You final query returns C.BUSINESS_PARTY_ID which is not transformed by Case. Your case statement also draws on BUSINESS_PARTY_ID. Did you mean to have C.CUIT instead of C.BUSINESS_PARTY_ID in your outer select statement?
long story short, i moved the case withing to a where statement from table C and added a userdefined value for the gregorian:
SELECT C.GREGORIAN_MONTH_ID
,C.BUSINESS_PARTY_ID
,C.TOTAL_MONTO
,C.Capitas_Puntuales
,C.CUIT
,nb_apellido
,nb_oficial_actual
,nb_cne_obe
,nb_nodo
,nb_territorio
,cd_area_negocio
FROM (SELECT gregorian_month_id
,business_party_id
,Case when BUSINESS_PARTY_ID in (88888,200) then '9999999999999' else business_party_ident_num end CUIT
,SUM(amt_accum) Total_Monto
,count(*) Capitas_Puntuales
FROM dbsreg.A127932_PARTY_MAIN_PAYROLL_HISTORY
where gregorian_month_id= ?FECHA_BASE
group by 1,2,3
) C
LEFT JOIN
(select NU_CUIT, nb_apellido,nb_oficial_actual, nb_cne_obe, nb_nodo, nb_territorio,cd_area_negocio
,(fh_corte/100 + 190000) gregorian_month_id
from dbsreg.a119527_base_info_gerencial
where gregorian_month_id = (Case when ?FECHA_BASE = (gregorian_month_id) then gregorian_month_id else gregorian_month_id-1 end )
) G
on C.CUIT = G.NU_CUIT
ORDER BY C.BUSINESS_PARTY_ID

Change phone number format

I have phone number field in database. It has already data.
I want to change my phone number format to "XXX-XXX-XXXX"
Current database has no any phone format.
So there may be garbage data. I have already applied validation for new records but now I want to change my existing data also.
Is there any specific way through that I can change my existing data. And make all phone numbers to follow this format.
Please advice.
Create function to remove the non-numeric data and do the formatting
CREATE FUNCTION [UDF_STRIP_NONNUMERIC_DATA](#str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
WHILE Patindex('%[^0-9]%', #str) > 0
BEGIN
SET #str = Stuff(#str, Patindex('%[^0-9]%', #str), 1, '')
END
RETURN #str
END
You can use STUFF function to inset the - between phone number
Select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
From yourtable
If you are using SQL SERVER 2012+ use can use FORMAT function (thanks to LukStorms, who mentioned it in comment)
SELECT Format(Cast(dbo.[Udf_strip_nonnumeric_data](Phone) AS BIGINT), '###-###-####')
FROM yourtable
To update
Update yourtable
SET phone = left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
Demo
declare #str varchar(100)= '9225-123-4567'
select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](#str),4,0,'-'),8,0,'-'),12)
Result : 922-512-3456
declare #phone varchar(24)
set #phone = '(334)789-4532'
--set #phone = '314789-4532'
--set #phone = '3457894532'
--set #phone = '534-789-4532'
SELECT
LEFT(N,3) + '-' + SUBSTRING(N,4,3) + '-' + RIGHT(N,4)
FROM
(SELECT CAST(CAST((
SELECT SUBSTRING(#phone, Number, 1)
FROM master..spt_values
WHERE Type='p' AND Number <= LEN(#phone) AND
SUBSTRING(#phone, Number, 1) LIKE '[0-9]' FOR XML Path(''))
AS xml) AS varchar(MAX)) as N) as N
Ok, to replace all non-numeric characters, look at this.
Here is a sample script (copied from that link) to show you how it works (You'll need to modify this to fit your table name and column names:
-- Step 1: creates table to use to hold every char in every phone number
if object_id('dbo.tally') is not null drop table dbo.tally
select top 10000 --change to fit max length of phone number
identity(int,1,1) as n
into dbo.tally
from master.dbo.syscolumns sc1,
master.dbo.syscolumns sc2
-- add pk to maximize performance
alter table dbo.tally
add constraint pk_tally_n
primary key clustered (n) with fillfactor = 100
-- Step 2: Create temporary table holding three bad phone numbers
declare #phonetable table
(uniqueid int identity(1,1),
phone_number varchar(500))
insert into #phonetable (phone_number)
select '01234-567-890' union
select '012345 6789ext' union
select 'n/a' union select '...12345.....';
-- Step 3: identify, for every character, whether it is a number or not,
and remove the non-numeric ones
with cte (uniqueid, phone_number, goodchar, badchar) as
( select uniqueid, phone_number,
case when substring(phone_number,N,1) not like '%[^0-9]%'
then substring(phone_number,N,1) end as goodchar,
case when substring(phone_number,N,1) like '%[^0-9]%'
then substring(phone_number,N,1) end as badchar
from #phonetable , Tally
where phone_number like '%[^0-9]%' and N <= len(phone_number) )
select distinct phone_number,
isnull( stuff (
( SELECT '' + goodchar
FROM cte t1
where t1.UniqueID = t2.UniqueID
FOR XML PATH ( '' ) ) , 1 , 0 , '' ) ,'')
as clean_phone_number from cte t2
to display the numbers with formatting, just extract the appropriate pieces and re-concatenate them with the dashes.
Select case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
To create a computed column
Alter table Add Column FormattedPhone as
case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
If you don't mind a UDF
Select [dbo].[udf-Str-Format-Phone]('334)789-4532')
Returns
334-789-4532
The UDF
CREATE FUNCTION [dbo].[udf-Str-Format-Phone] (#S varchar(max))
Returns varchar(25)
AS
Begin
Declare #Return varchar(25)
;with cte0(N) As (Select 1 From (Values(1),(1),(1),(1),(1)) N(N))
, cteN(N) As (Select Top (Len(#S)) Row_Number() over (Order By (Select NULL)) From cte0 N1, cte0 N2)
, cteS(S) As (Select Substring(#S,N,1) From cteN Where Substring(#S, N, 1) LIKE '[0-9]' FOR XML Path(''))
Select #Return = IIf(Len(S)>=10,Stuff(stuff(S,4,0,'-'),8,0,'-'),Stuff(S,4,0,'-')) From cteS
Return #Return
End
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('(334)789-4532') -- Returns 334-789-4532
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('Phone:7894532') -- Returns 789-4532

Verify existence of two columns in different tables in a single SQL transaction

I'm trying to verify if data exists in two different tables in a single transaction. The reason for the single transaction is the database gets hit about 1-3 million times a day so adding anymore than 1 extra transaction would increase that number up to 9 million, and my poor little server needs a break :)
So I need to check if an ID exists in table X and table Y and return the results to my VB.net script so I can handle the outcome Ideally something like this would work
if exists (select id from X where id = #id)
print 'True,' else print 'False,'
if exists (select id from Y where id = #id)
print 'True' else print 'False'
Which gives me "True, True" if exists in both or "True, False" etc etc... But that only displays in SQL print and not actually returning it as an object/string or array values that I can use.
I'm open to any sort of solution of this nature that can give me two results from a single transaction and how to handle that response in vb. Thanks
SELECT
Case When EXISTS(SELECT 1 FROM X WHERE id = #id) Then 1 Else 0 End AS IsInX,
Case When EXISTS(SELECT 1 FROM Y WHERE id = #id) Then 1 Else 0 End AS IsInY
select (select COUNT(*) from X where id = #id) AS x_exists,
(select COUNT(*) from Y where id = #id) AS y_exists
This returns one data row with two fields, each containing either 0 or 1 (or more, if id is not unique).
CREATE PROCEDURE CheckIDOnTables(#ID int)
AS
BEGIN
DECLARE #X AS NVARCHAR(10)
DECLARE #Y AS NVARCHAR(10)
Set #X = 'False'
Set #Y = 'False'
if exists (select id from TableX where id = #ID)
Set #X = 'True'
if exists (select id from TableY where id = #ID)
Set #Y = 'True'
SELECT #X AS XExists, #Y AS YEsists
END
It will give you your desired results.

Pl/SQL - oracle 9i - Manual Pivoting

We have a table which has three columns in it:
Customer_name, Age_range, Number_of_people.
1 1-5 10
1 5-10 15
We need to return all the number of people in different age ranges as rows of a single query. If we search for customer #1, the query should just return one row:
Header- Age Range (1-5) Age Range (5-10)
10 15
We needed to get all the results in a single row; When I query for customer 1, the result should be only number of people in a single row group by age_range.
What would be the best way to approach this?
You need to manually perform a pivot:
SELECT SUM(CASE WHEN age_range = '5-10'
THEN number_of_people
ELSE NULL END) AS nop5,
SUM(CASE WHEN age_range = '10-15'
THEN number_of_people
ELSE NULL END) AS nop10
FROM customers
WHERE customer_name = 1;
There are easy solutions with 10g and 11g using LISTGAGG, COLLECT, or other capabilities added after 9i but I believe that the following will work in 9i.
Source (http://www.williamrobertson.net/documents/one-row.html)
You will just need to replace deptno with customer_name and ename with Number_of_people
SELECT deptno,
LTRIM(SYS_CONNECT_BY_PATH(ename,','))
FROM ( SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS seq
FROM emp )
WHERE connect_by_isleaf = 1
CONNECT BY seq = PRIOR seq +1 AND deptno = PRIOR deptno
START WITH seq = 1;
DEPTNO CONCATENATED
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
This will create a stored FUNCTION which means you can access it at any time.
CREATE OR REPLACE FUNCTION number_of_people(p_customer_name VARCHAR2)
RETURN VARCHAR2
IS
v_number_of_people NUMBER;
v_result VARCHAR2(500);
CURSOR c1
IS
SELECT Number_of_people FROM the_table WHERE Customer_name = p_customer_name;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO v_number_of_people;
EXIT WHEN c1%NOTFOUND;
v_result := v_result || v_number_of_people || ' ' || CHR(13);
END;
END;
To run it, use:
SELECT number_of_people(1) INTO dual;
Hope this helps, and please let me know if there are any errors, I didn't testrun the function myself.
Just do
select Number_of_people
from table
where Customer_name = 1
Are we missing some detail?

Resources