T-SQL Dynamic Query and pivot - sql-server

I have data where people have changed role mid month and want to count the activity after their new start date. Can I use the results of a table as a dynamic Query, I have a query which returns the following resultset:-
Firstname Surname StartDate
----------------------------------
Jon Smith 2015-01-01
Paul Jones 2014-07-23
...
So the query would look something like:
SELECT Firstname +' '+ surname, month, count(1) FROM dataTable
WHERE (Firstname='John' AND Surname='Smith' AND date >=2015-01-01)
OR (Firstname='Paul' AND Surname='Jones' AND date >=2014-07-23)
OR ...
but the number of 'ORs' would depend on the number of rows in the first table
Name Month Count
----------------------------------
Jon Smith 1 15
Paul Jones 1 16
Jon Smith 2 30
Paul Jones 2 25
Charlie Gu 1 52
Which I can then pivot to get
Name 1 2
--------------------------
Jon Smith 15 30
Paul Jones 16 25
Charlie Gu 52 NULL
Thanks in advance

It seems to me that Ako is right and a simple join should do the trick rather than a dynamic query.
declare #NewStartDates table
(
Firstname nvarchar(100),
Surname nvarchar(100),
StartDate date
);
insert into #NewStartDates
(Firstname, Surname, StartDate)
values (N'Jon', N'Smith', '20150101'),
(N'Paul', N'Jones', '20140723');
select d.Firstname,
d.Surname,
year(d.Date) * 100 + month(d.Date) as Period,
count(*) as ActivityCount
from dataTable as d
inner join #NewStartDates as n
on d.Firstname = n.Firstname
and d.Surname = n.Surname
and d.Date >= n.StartDate
group by d.Firstname,
d.Surname,
year(d.Date) * 100 + month(d.Date);

Please refer this - it will give you complete idea how you can get dynamic column query.Dynamic Column Generation - Pivot [SQL]

Related

SQL Pivot / Case Query based on Row Value

Problem
Using SQL Server, I'm trying to pivot data based on values in a column. I want to move Bob and John's value column over if Salary is in the metric column.
Sample data:
Person table
Person ID
-------------
Bob 1
Bob 1
John 2
John 2
Value table
Metric Value ID
---------------------
Age 52 1
Salary 60000 1
Age 45 2
Salary 55000 2
Expected output
My goal is to pivot the table if salary is present in the Metric column.
Person Metric Value Salary ID
---------------------------------------
Bob Age 52 60000 1
John Age 45 55000 2
Current code:
SELECT *
FROM person_table pt, value_table vb
WHERE pt.id = vb.id
AND vb.metric IN ('Age', 'Salary')
Use the following pivot query:
SELECT
pt.Person,
'Age' AS Metric,
MAX(CASE WHEN vb.Metric = 'Age' THEN vb.Value END) AS Value,
MAX(CASE WHEN vb.Metric = 'Salary' THEN vb.Value END) AS Salary,
pt.ID
FROM person_table pt
INNER JOIN value_table vb
ON pt.id = vb.id
GROUP BY
pt.Person,
pt.ID
ORDER BY
pt.ID;

Execute select statement within an IF clause Oracle

This is a query from SQL Server, what I want to ask is, how do I want to get the same result in Oracle, what would be the query?
I need result like this: 'this is query on SQL Server'
declare #a int = 6
if #a = 1
begin
select *
from table_A
end
else
begin
select *
from table_B
end
I have tried like this on oracle but failed
declare
type FF_rec is record(
st_Value number
);
var_ff FF_rec;
begin
var_ff.st_Value:=1;
if 1<=0 then
select * from Table_A;
else
select * from Table_B;
end if;
end;
If it has to be at SQL level, then maybe you can use such a code: depending on a value passed to PAR_WHAT substitution variable, you'll get result from EMP or DEPT table.
Because of UNION set operator, select column lists must match in number and datatype,
i.e.
you can't select e.g. two columns from the 1st select and 5 columns from the 2nd;
nor can they not be matched in datatype, e.g. 1st column of 1st select is DATE, while 1st column of 2nd select is NUMBER
So:
SQL> select empno, ename, job
2 from emp
3 where &&par_what = 1
4 union
5 select deptno, dname, loc
6 from dept
7 where &&par_what = 2;
Enter value for par_what: 1
EMPNO ENAME JOB
---------- -------------- -------------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
7566 JONES MANAGER
7654 MARTIN SALESMAN
<snip>
14 rows selected.
SQL> undefine par_what
SQL> /
Enter value for par_what: 2
EMPNO ENAME JOB
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
If you're OK with PL/SQL, then one option is to create a function that returns refcursor. Which one? Depends on parameter you pass to it:
SQL> create or replace function f_test (par_what in number)
2 return sys_refcursor
3 is
4 l_rc sys_refcursor;
5 begin
6 if par_what = 1 then
7 open l_rc for select deptno, ename, job, sal, hiredate from emp;
8 elsif par_what = 2 then
9 open l_rc for select deptno, dname, loc from dept;
10 end if;
11
12 return l_rc;
13 end;
14 /
Function created.
Testing:
SQL> select f_test(1) from dual;
F_TEST(1)
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DEPTNO ENAME JOB SAL HIREDATE
---------- ---------- --------- ---------- ----------
20 SMITH CLERK 800 17.12.1980
30 ALLEN SALESMAN 1600 20.02.1981
30 WARD SALESMAN 1250 22.02.1981
20 JONES MANAGER 2975 02.04.1981
30 MARTIN SALESMAN 1250 28.09.1981
30 BLAKE MANAGER 2850 01.05.1981
<snip>
14 rows selected.
SQL> select f_test(2) from dual;
F_TEST(2)
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>

How to find the difference between two table in database without using join?

I need to find the difference between highest salary from a table called myproject.faculty and the highest salary from a table called myproject.staff. How can I do that?
SQL Query:
SELECT *
FROM myproject.faculty
Result:
ID FIRSTNAME LASTNAME CITY STATE ZIP SALARY DEPT BIRTH_DATE PHONE
102 Jack Sue Frostburg MD 21532 109000 COSC 3016783232
1 Jo Andorfer Aberdeen MD 21532 80000.89 COSC 01-FEB-81 301-687-5678
SQL Query:
SELECT *
FROM myproject.staff
Result:
ID FIRSTNAME LASTNAME CITY STATE ZIP SALARY BIRTH_DATE PHONE
1 Xin Zheng Aberdeen MD 21532 80000.89 01-FEB-81 301-687-5678
2 Gerri Wojnar Aberdeen FL 33423 78000.25 22-JAN-88 301-687-5679
Try following
select (select max(salary) from myproject.faculty) - (select max(salary) from myproject.staff)

SQL server select one record per day based on value in field

I have a followup question to this question.
SQL Server Get values of top three records and display in one row per person
ID Name Date1 Value2 Date2 Value2 Date3 Value3 Date4 Value4 Date5 Value5 Date6 Value6 Date7 Value7
12 John Smith 2011-06-27 14:06:10.517 None 2011-06-27 00:17:53.987 None 2011-06-26 21:56:07.577 Medium 2011-06-26 13:32:31.190 None 2011-06-26 02:47:54.357 None 2011-06-25 19:32:00.000 Medium 2011-06-25 13:43:22.000 Medium
12 Jack Smith 2011-06-27 05:54:59.320 None 2011-06-26 06:28:55.033 None 2011-06-25 16:25:00.000 Medium 2011-06-25 14:27:11.017 Large 2011-06-25 06:11:45.793 Large 2011-06-24 19:33:24.520 Medium 2011-06-24 06:17:35.887 None
I need to get one value per day. If there is a value that is not equal to 'None', I need that record for the given date.
Here is what the outcome should look like:
ID Name Date1 Value2 Date2 Value2 Date3 Value3 Date4 Value4 Date5 Value5 Date6 Value6 Date7 Value7
12 John Smith 2011-06-27 00:17:53.987 None 2011-06-26 21:56:07.577 Medium 2011-06-25 13:43:22.000 Medium
12 Jack Smith 2011-06-27 05:54:59.320 None 2011-06-26 06:28:55.033 None 2011-06-25 06:11:45.793 Large 2011-06-24 19:33:24.520 Medium
My raw data is in this format:
(Records I need are marked with *)
ID Name Date Value
12 JACK Smith 2011-06-27 05:54:59.320 None *
12 JACK Smith 2011-06-26 06:28:55.033 None *
12 JACK Smith 2011-06-25 16:25:00.000 Medium
12 JACK Smith 2011-06-25 14:27:11.017 Large
12 JACK Smith 2011-06-25 06:11:45.793 Large *
12 JACK Smith 2011-06-24 19:33:24.520 Medium *
12 JACK Smith 2011-06-24 06:17:35.887 None
12 JACK Smith 2011-06-23 00:30:28.363 None *
12 JACK Smith 2011-06-22 00:47:41.800 None *
12 JACK Smith 2011-06-21 06:03:55.000 None *
Any help is greatly appreciated.
Not clear what you're asking...
You can restrict your recordset with a WHERE clause (this will remove the record entirely)...probably easier to do this on your original recordset (at the link you posted) than on this revised recordset above...
WHERE value <> 'None'
Or you can keep the record, and just restrict the display with a function (many options -- here's one:)
Replace('None','')
...here's another one:
CASE value WHEN 'None' THEN '' ELSE value END
Something like this then... It will work, but it might have a typo, as I'm just typing it out without testing.
SELECT
ID,
Name,
Right(
-- The Right() function will strip-off the leading integer that you need to first add to the date so
-- you can get the record you want.
Min(
-- The Min() function will get a single record for you
-- the functions below will manipulate the date so that records with a non-'None' value are
-- guaranteed to have a larger date then records with a 'None' value. This is done by adding
-- an integer to the front of the date -- '0' for non-'None' values, and '1' for 'None' values.
Cast(CASE value WHEN 'None' THEN 1 ELSE 0 END as varchar(1))
-- The CASE statement outputs a 0 or 1
-- The Cast() function changes the output to text instead of a number, so you can use the
-- string concat (+) later.
+
-- string concatenation, which only works on text, not numbers
Cast(Date as varchar(25))
-- The Cast() function changes the date to text, so you can use it with the string concat above
)
, 23
-- 23 should be the number of characters in the date itself
-- adjust the number up or down as necessary.
) as myDate,
Value
FROM
Table
GROUP BY
ID,
Name,
Value
This should reduce your original recordset so that it only contains the records you want. Afterward, you can apply the horizontal solution that the #Manfred Sorg came-up with for your first question.
you want do transposition, i guess.
you should use pivot table some how that
table: pivot
values: 0, 1, 2, ...
the idea be able to position each value the each day in correct column and after group for get one single row
after you need do query
select
resultset.id, resultset.Name,
case when not max(date1) is null then max(date1)
else null end as date1,
case when not max(value1) is null then max(value1)
else '' end as value1,
...
...
...
from (
select mltwngd.id, mltwngd.Name,
//sorry that part is ugly, ugly,
case when i=0 then datedd(day, mltwngdg.periodstart, auxtable.i)
else '' end as date1,
case when i=0 then datedd(day, mltwngdg.periodstart, auxtable.i)
else '' end as value1,
...
...
...
from mylinealtable_with_nogooddesing mltwngd
inner join
(
select id, min(date) periodstart,
max(date) as periodend,
datediff("dd", max(date), min(date)) as days
from mylinealtable_with_nogooddesing
where ...
group by id
) as mltwngdg
on mltwngdg.id = mltwngd.id
inner join
(
select *
from pivot
where i >= 0 and i < #period_max_days
)auxtable
on auxtable.i >0 and auxtable.i < days
)resultset
group by resultset.id, resultset.Name
the idea simplified is
declare #aux table (id int, [name] varchar(20),
date1 datetime,
valor1 varchar(10),
date2 datetime,
valor2 varchar(10)
)
insert into #aux(id, [name], date1, valor1, date2, valor2)
values(1,'CARLOS','20110201','XP',NULL, '')
insert into #aux(id, [name], date1, valor1, date2, valor2)
values(1,'CARLOS',NULL, '','20110201','WIN7')
select * from #aux
select
x.id, x.name,
case when not max(date1) is null then max(date1)
else null end as date1,
case when not max(valor1) is null then max(valor1)
else null end as valor1,
case when not max(date2) is null then max(date2)
else null end as date2,
case when not max(valor1) is null then max(valor2)
else null end as valor2
from #aux x
group by x.id, x.name

SQL Server: displaying first line of grouped records

Am trying to write a query that would output something similar to the last batch of records below. For sure it works in Reporting Services and Crystal Reports, but just throwing it out here to see if it is possible in SSMS/QA:
Table:
id name amount
-- ---- ------
1 rob 23.00
2 rob 34.00
3 dan 45.00
4 dan 56.00
select name, amount from t1
Query resulting in:
name amount
---- ------
rob 23.00
rob 34.00
dan 45.00
dan 56.00
DESIRED result:
name amount
---- ------
rob 23.00
34.00
dan 45.00
56.00
Thanks!
Try this:
SELECT CASE WHEN _rank = 1 THEN name ELSE '' END AS name, amount
FROM (
SELECT name, amount,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY amount ASC) AS _rank
FROM t1
) q

Resources