PIVOT with Multiple Dates inside "IN" clause - mysql

I have here some problem on inserting multiple dates inside in clause.
Here is the code that I have seen through the internet research.
;with cte (datelist, maxdate) as
(
select min(arrivaldate) datelist, max(departuredate) maxdate
from BookingsPerPerson
union all
select dateadd(dd, 1, datelist), maxdate
from cte
where datelist < maxdate
)
select c.datelist
into #tempDates
from cte c
select *
from
(
select b.person_id, b.arrivaldate, b.departuredate,
d.datelist,
convert(CHAR(10), datelist, 120) PivotDate
from #tempDates d
left join BookingsPerPerson b
on d.datelist between b.arrivaldate and b.departuredate
) x
pivot
(
count(datelist)
for PivotDate in ([2012-01-01], [2012-01-02], [2012-01-03],
[2012-01-04], [2012-01-05], [2012-01-06] , [2012-01-07])
) p;
Since the code is manually adding the dates inside the IN clause
pivot
(
count(datelist)
for PivotDate in ([2012-01-01], [2012-01-02], [2012-01-03],
[2012-01-04], [2012-01-05], [2012-01-06] , [2012-01-07])
) p;
Can I just use the date which is extract/split by this code
;with cte (datelist, maxdate) as
(
select min(arrivaldate) datelist, max(departuredate) maxdate
from BookingsPerPerson
union all
select dateadd(dd, 1, datelist), maxdate
from cte
where datelist < maxdate
)
select c.datelist
into #tempDates
from cte c
And use the SELECT statement on the "IN" clause inside the pivot statement?
like this?
pivot
(
count(datelist)
for PivotDate in (select c.datelist from #tempDates)
) p;
I tried this but it gives me an error?
Is there any way that I can add multiple dates from
a temporary table and include it inside the IN clause?
YOU CAN TRY IT HERE : http://sqlfiddle.com/#!3/8857c/9

Yes there is a way. you place first the concatenated dates in one variable..
for example:
DECLARE #dateArray AS VARCHAR(500)
SELECT #dateArray = '02/01/2014,02/02/2014,02/03/2014,02/04/2014'
then create a dynamic sql query:
set #query = 'SELECT * FROM TABLE
PIVOT (count(datelist) PivotDate in (' + #dateArray + '))
hope it helped you in a way. :)

Related

How to process multiple record with same id into single record with login / logout time in SQL?

is this possible to make a "newtable" from "oldtable" like a picture down below?
Use PIVOT method :
Declare #table table (id varchar(10),[time] time)
insert into #table
SELECT '01','10:08:23'
UNION ALL
SELECT '02','10:10:50'
UNION ALL
SELECT '01','13:30:00'
SELECT *
FROM
(
SELECT id , time , CASE WHEN MIN(RNo) = 1 THEN 'CheckIn' WHEN MAX(RNo) >
1 THEN 'CheckOut' END Type
FROM
(
SELECT * , ROW_NUMBER() OVER (PARTITION BY id ORDER BY time) RNo
FROM #table
) A
GROUP BY id , time
) A
PIVOT
(
MAX(time) FOR Type IN ([CheckIn],[CheckOut])
)Pvt
This can be use for matching column (s)
INSERT INTO `NEWTABLE`(`id`, `check in`)
SELECT o.id, o.time FROM OLDTABLE o

wrong result mysql in function only

I have the following function, mysql query:
BEGIN
DECLARE r float(10,2);
DECLARE var_total float(10,2);
DECLARE var_discount float(10,2) DEFAULT null;
SELECT
sum(x.amount)
FROM
(
(SELECT
student_booking_school_course_price as amount
FROM
tbl_student_booking_school_course
WHERE
student_booking_id=par_student_booking_id
)
UNION
(SELECT
student_booking_school_accommodation_price as amount
FROM
tbl_student_booking_school_accommodation
WHERE
student_booking_id=par_student_booking_id
)
UNION
(SELECT
student_booking_school_insurance_price as amount
FROM
tbl_student_booking_school_insurance
WHERE
student_booking_id=par_student_booking_id
)
UNION
(SELECT
student_booking_school_transfer_price as amount
FROM
tbl_student_booking_school_transfer
WHERE
student_booking_id=par_student_booking_id
)
) x
INTO var_total;
IF var_total IS NULL THEN
SET r = 0;
END IF;
-- discount
SET var_discount = (SELECT
sb.student_booking_discount_amount
FROM
tbl_student_booking sb
WHERE
sb.student_booking_id=par_student_booking_id LIMIT 1);
IF var_discount IS NOT NULL THEN
SET r = var_total - var_discount;
end if;
return r;
END
The values are:
9698.88 course
559.55 accommodation
559.55 insurance
145.98 discount
It seems that the first query inside the function, only sums distinct values, as the result with discount is: 10112.45, so is not summing one value of 559.55, I tried to output different things as concat with a string and only see the result as 9698.88course,559.55accommodation, etc.. and it is fine. So I assume the issue is that is not summing if values are equals. The strange thing is that running this from the console, only the query outside the function, it sums ok.
My question is this a normal behaviour of MySql?If so is there a way to prevent this? is this a bug?
What you need here is UNION ALL clause:
SELECT
sum(x.amount)
FROM
(
(SELECT
student_booking_school_course_price as amount
FROM
tbl_student_booking_school_course
WHERE
student_booking_id=par_student_booking_id
)
UNION ALL
(SELECT
student_booking_school_accommodation_price as amount
FROM
tbl_student_booking_school_accommodation
WHERE
student_booking_id=par_student_booking_id
)
UNION ALL
(SELECT
student_booking_school_insurance_price as amount
FROM
tbl_student_booking_school_insurance
WHERE
student_booking_id=par_student_booking_id
)
UNION ALL
(SELECT
student_booking_school_transfer_price as amount
FROM
tbl_student_booking_school_transfer
WHERE
student_booking_id=par_student_booking_id
)
) x
INTO var_total;
The MySQL UNION Documentation says:
A DISTINCT union can be produced explicitly by using UNION DISTINCT or
implicitly by using UNION with no following DISTINCT or ALL keyword.

Pivot With Calendar Table

I am trying to pivot this data but I am getting an error of
Msg 102, Level 15, State 1, Line 16
Incorrect syntax near ','.
Highlighting the comma after SUM([Total Count]) but it has to be there, what should I change so my query executes properly?
select *
FROM
(
select a.regionalLocale As [RL],
Count(ID) As [Total Count],
CONVERT(VARCHAR(20), dt.week) AS Week
FROM database14.dataTable a
INNER JOIN calendarDB.masterCalendar dt
ON a.SaleDate = dt.FullDate
WHERE a.SaleDate IS NOT NULL
) src
pivot
(
SUM([Total Count]), [RL]
For Week IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
) piv
You've got a few issues with your query.
One you've got the syntax SUM([Total Count]), [RL] in your PIVOT. You only want to include the column you are aggregating here.
Second, there is no need to use count(id) inside your subquery, let the PIVOT aggregation handle the total. Change your code to:
select [RL],
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13]
FROM
(
select a.regionalLocale As [RL],
ID,
CONVERT(VARCHAR(20), dt.week) AS Week
FROM database14.dataTable a
INNER JOIN calendarDB.masterCalendar dt
ON a.SaleDate = dt.FullDate
WHERE a.SaleDate IS NOT NULL
) src
pivot
(
COUNT(ID)
For Week IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
) piv

How many different ways are there to get the second row in a SQL search?

Let's say I was looking for the second most highest record.
Sample Table:
CREATE TABLE `my_table` (
`id` int(2) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`value` int(10),
PRIMARY KEY (`id`)
);
INSERT INTO `my_table` (`id`, `name`, `value`) VALUES (NULL, 'foo', '200'), (NULL, 'bar', '100'), (NULL, 'baz', '0'), (NULL, 'quux', '300');
The second highest value is foo. How many ways can you get this result?
The obvious example is:
SELECT name FROM my_table ORDER BY value DESC LIMIT 1 OFFSET 1;
Can you think of other examples?
I was trying this one, but LIMIT & IN/ALL/ANY/SOME subquery is not supported.
SELECT name FROM my_table WHERE value IN (
SELECT MIN(value) FROM my_table ORDER BY value DESC LIMIT 1
) LIMIT 1;
Eduardo's solution in standard SQL
select *
from (
select id,
name,
value,
row_number() over (order by value) as rn
from my_table t
) t
where rn = 1 -- can pick any row using this
This works on any modern DBMS except MySQL. This solution is usually faster than solutions using sub-selects. It also can easily return the 2nd, 3rd, ... row (again this is achievable with Eduardo's solution as well).
It can also be adjusted to count by groups (adding a partition by) so the "greatest-n-per-group" problem can be solved with the same pattern.
Here is a SQLFiddle to play around with: http://sqlfiddle.com/#!12/286d0/1
This only works for exactly the second highest:
SELECT * FROM my_table two
WHERE EXISTS (
SELECT * FROM my_table one
WHERE one.value > two.value
AND NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
)
LIMIT 1
;
This one emulates a window function rank() for platforms that don't have them. It can also be adapted for ranks <> 2 by altering one constant:
SELECT one.*
-- , 1+COALESCE(agg.rnk,0) AS rnk
FROM my_table one
LEFT JOIN (
SELECT one.id , COUNT(*) AS rnk
FROM my_table one
JOIN my_table cnt ON cnt.value > one.value
GROUP BY one.id
) agg ON agg.id = one.id
WHERE agg.rnk=1 -- the aggregate starts counting at zero
;
Both solutions need functional self-joins (I don't know if mysql allows them, IIRC it only disallows them if the table is the target for updates or deletes)
The below one does not need window functions, but uses a recursive query to enumerate the rankings:
WITH RECURSIVE agg AS (
SELECT one.id
, one.value
, 1 AS rnk
FROM my_table one
WHERE NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
UNION ALL
SELECT two.id
, two.value
, agg.rnk+1 AS rnk
FROM my_table two
JOIN agg ON two.value < agg.value
WHERE NOT EXISTS (
SELECT * FROM my_table nx
WHERE nx.value > two.value
AND nx.value < agg.value
)
)
SELECT * FROM agg
WHERE rnk = 2
;
(the recursive query will not work in mysql, obviously)
You can use inline initialization like this:
select * from (
select id,
name,
value,
#curRank := #curRank + 1 AS rank
from my_table t, (SELECT #curRank := 0) r
order by value desc
) tb
where tb.rank = 2
SELECT name
FROM my_table
WHERE value < (SELECT max(value) FROM my_table)
ORDER BY value DESC
LIMIT 1
SELECT name
FROM my_table
WHERE value = (
SELECT min(r.value)
FROM (
SELECT name, value
FROM my_table
ORDER BY value DESC
LIMIT 2
) r
)
LIMIT 1

How to add time (like 9:25:03 + 11:36:27 = ) of single column in sql server 2008

i have column(time datatype) which contains values like
9:25:03
4:43:21
2:50:13
11:25:33
,what query should i write to get sum of all values in the column
try this:
;with cte as(
select SUM(DATEPART(hh,tm))*3600+
SUM(DATEPART(MI,tm))*60+
SUM(DATEPART(SS,tm)) tme
from time_table)
SELECT cast(datepart(hh,cast(CONVERT(varchar(8),
DATEADD(ss, tme , 0), 114) as time))+
datediff(dd,'1900-01-01',CONVERT(varchar,
DATEADD(ss, tme , 0), 121))*24 as varchar(20))+
right(CONVERT(varchar(8), DATEADD(ss, tme , 0), 114),6)
from cte
result
28:24:10
SQL Fiddle demo
Turn your times into seconds and sum them instead.
with YourTable(TimeCol) as
(
select '9:25:03' union all
select '4:43:21' union all
select '2:50:13' union all
select '11:25:33'
)
select sum(datediff(second, 0, TimeCol)) sumSeconds
from YourTable
Result:
sumSeconds
-----------
102250
try this:
create table tbl123(tm time)
insert into tbl123
values('9:25:03'),('4:43:21'),('2:50:13'),('11:25:33')
;WITH CTE as(select SUM(DATEPART(hh,tm)) as hh,SUM(DATEPART(mi,tm)) as mm,SUM(DATEPART(ss,tm)) as ss from tbl123)
SELECT cast(hh+(mm+(ss/60))/60 as varchar(10))+':'+
cast((((mm+(ss/60))%60)) as varchar(10))+':'+
cast(ss%60 as varchar(10))
from CTE
Result:
28:24:10