Summary of inner group in a cell in the outer group - sql-server-2008

I have a section of a report that has an outer group with an inner group. Some of my users will print this report while some will not. I'd like to be able to to keep the toggle capabilities while providing a summary on the outer group of the top 3 rows of the inner group. Basically, I'd like the notes column to see the top three defects and their total counts.
I could accomplish this by doing the work in SQL, but in this case I'd prefer, if possible, for the report server to handle the summary and grouping.
Outer Group Sum(Defects) First(DefectId)
Inner Group Sum(Defects)

Ended up using CTE
with MyCte AS (SELECT
MachineCode + ' | ' + Tool + ' | ' + comments + ' | ' + Operator + ' | ' + convert(nvarchar(50), MinutesDown) + ' ||| ' 'Things',
Reason,
MinutesDown,
PartitionedRowNum = ROW_NUMBER() OVER (PARTITION BY Reason ORDER BY MinutesDown DESC)
from #Comments)
insert into #t
select *
from MyCte
where PartitionedRowNum <= 3

Related

MYSQL: Join list of values into a table

I have list of predefined values Cash, Bank, Card, Cheque called payment modes (no db table for them).
Each payments will have it's mode.
+-----------+
+ Payments +
+-----------+
+ id +
+ amount +
+ date +
+ mode +
+-----------+
The below query will not show mode that are not in the payments table. If for example no payment is made through cheque, then it will not be in the result.
select p.mode, SUM(p.amount) 'total'
from payments p
I also found out about Table Value Constructor but I'm not sure if its supported in MySql as I'm having syntax error.
select p.mode, SUM(p.amount)
from (
VALUES
('Cash'),
('Card'),
('Cheque'),
('Bank')
) as m(name)
left join payments p on m.name = p.mode
group by p.mode
Is there a way to have a query that gets all the mode regardless if they are not present in the payments table? I need a result like:
++++++++++++++++++++
+ mode | total +
++++++++++++++++++++
+ cash | 100 +
+ cheque | 0 +
+ bank | 0 +
+ card | 300 +
++++++++++++++++++++
In MySQL, you can construct the table using union all:
select m.mode, SUM(p.amount)
from (select 'Cash' as mode union all
select 'Card' union all
select 'Cheque' union all
select 'Bank'
) m left join
payments p
on m.mode = p.mode
group by m.mode;
Notes:
I changed name to mode so the column with the same information has the same name.
The group by key needs to be from the first name, not the second (that is m.mode instead of p.mode).
If you want 0 instead of NULL, then use coalesce(sum(p.amount), 0).
You might want to consider a reference table that contains the mode values.
select
m.mode,
SUM(p.amount)
FROM
(
SELECT
m.Cash as mode
FROM
(
VALUES
('cash'),
('card'),
('cheque'),
('bank')
) as m
) as m
left join payments p on m.mode = p.mode
group by
m.mode
You need two aliases and you must use the first value of your array (Cash) in nested select as selected column.
It's worth checking your version of MySQL if the VALUES approach isn't working. It was only introduced from MySQL 8.0.19 , so anyone on an earlier issue will need to use the UNION ALL approach.

mysql -get data who complete within a year

I need to get date who finish within 1 year from a project . my project table contain 'Sdate ' and 'Edate' which I can I need to use it to find data who finish within 1 year how do I get data within a year. For example I need to get data who have finish the project within 1 year (different is within 1 year)
This is what I have tried
SELECT
concat(FName, ' ', LName) AS NAME
FROM
Employee
WHERE
EXISTS (
SELECT
DATE_SUB(Sdate, INTERVAL 1 YEAR) AS DIFF
FROM
Project
);
You can change the joined field based on your table column name and try below query -
SELECT
concat(e.FName, ' ', e.LName) AS NAME
FROM
Employee e
JOIN project p ON e.employeeId = p.employeeId
WHERE
p.Sdate >= DATE_SUB(p.Edate, INTERVAL 1 YEAR)
GROUP BY
e.id;
If you want to use exists function then use below query-
select concat(e.FName , ' ' , e.LName) as name
From Employee e
where exists(select * from product p where e.employeeId=p.employeeId and p.Sdate >= DATE_SUB(p.Edate,INTERVAL 1 YEAR)) group by e.id;

Select first and last match by column from a timestamp-ordered table in MySQL

Stackoverflow,
I need your help!
Say I have a table in MySQL that looks something like this:
-------------------------------------------------
OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION
-------------------------------------------------
1|1|123456|2016-01-01 00:00:00|A
1|2|123456|2016-01-01 00:01:00|B
1|3|123456|2016-01-01 00:02:00|C
1|4|123456|2016-01-01 00:03:00|C
1|5|123456|2016-01-01 00:04:00|B
1|6|123456|2016-01-01 00:05:00|A
1|7|123456|2016-01-01 00:06:00|A
...
1|999|123456|2016-01-01 09:10:00|A
1|1000|123456|2016-01-01 09:11:00|A
1|1001|123456|2016-01-01 09:12:00|B
1|1002|123456|2016-01-01 09:13:00|C
1|1003|123456|2016-01-01 09:14:00|C
1|1004|123456|2016-01-01 09:15:00|B
...
Please note that the table schema is just made up so I can explain
what I'm trying to accomplish...
Imagine that from ENTRY_ID 6 through 999, the LOCATION column is "A". All I need for my application is basically rows 1-6, then row 1000 onwards. Everything from row 7 to 999 is unnecessary data that doesn't need to be processed further. What I am struggling to do is either disregard those lines without having to move the processing of the data into my application, or better yet, delete them.
I'm scratching my head with this because:
1) I can't sort by LOCATION then just take the first and last entries, because the time order is important to my application and this will become lost - for example, if I processed this data in this way, I would end up with row 1 and row 1000, losing row 6.
2) I'd prefer to not move the processing of this data to my application, this data is superfluous to my requirements and there is simply no point keeping it if I can avoid it.
Given the above example data, what I want to end up with once I have a solution would be:
-------------------------------------------------
OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION
-------------------------------------------------
1|1|123456|2016-01-01 00:00:00|A
1|2|123456|2016-01-01 00:01:00|B
1|3|123456|2016-01-01 00:02:00|C
1|4|123456|2016-01-01 00:03:00|C
1|5|123456|2016-01-01 00:04:00|B
1|6|123456|2016-01-01 00:05:00|A
1|1000|123456|2016-01-01 09:11:00|A
1|1001|123456|2016-01-01 09:12:00|B
1|1002|123456|2016-01-01 09:13:00|C
1|1003|123456|2016-01-01 09:14:00|C
1|1004|123456|2016-01-01 09:15:00|B
...
Hopefully I'm making sense here and not missing something obvious!
#Aliester - Is there a way to determine that a row doesn't need to be
processed from the data contained within that row?
Unfortunately not.
#O. Jones - It sounds like you're hoping to determine the earliest and
latest timestamp in your table for each distinct value of ENTRY_ID,
and then retrieve the detail rows from the table matching those
timestamps. Is that correct? Are your ENTRY_ID values unique? Are they
guaranteed to be in ascending time order? Your query can be made
cheaper if that is true. Please, if you have time, edit your question
to clarify these points.
I'm trying to find the arrival time at a location, followed by the departure time from that location. Yes, ENTRY_ID is a unique field, but you cannot take it as a given that an earlier ENTRY_ID will equal an earlier timestamp - the incoming data is sent from a GPS unit on a vehicle and is NOT necessarily processed in the order they are sent due to network limitations.
This is a tricky problem to solve in SQL because SQL is about sets of data, not sequences of data. It's extra tricky in MySQL because other SQL variants have a synthetic ROWNUM function and MySQL doesn't as of late 2016.
You need the union of two sets of data here.
the set of rows of your database immediately before, in time, a change in location.
the set of rows immediately after a change in location.
To get that, you need to start with a subquery that generates all your rows, ordered by VEHICLE then TIME, with row numbers. (http://sqlfiddle.com/#!9/6c3bc7/2/0) Please notice that the sample data in Sql Fiddle is different from your sample data.
SELECT (#rowa := #rowa + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowa := 0) init
ORDER BY VEHICLE, TIME
Then you need to self-join that subquery, use the ON clause to exclude consecutive rows at the same location, and take the rows right before a change in location. Comparing consecutive rows is done by ON ... b.rownum = a.rownum+1. That is this query. (http://sqlfiddle.com/#!9/6c3bc7/1/0)
SELECT a.*
FROM (
SELECT (#rowa := #rowa + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowa := 0) init
ORDER BY VEHICLE, TIME
) a
JOIN (
SELECT (#rowb := #rowb + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowb := 0) init
ORDER BY VEHICLE, TIME
) b ON a.VEHICLE = b.VEHICLE
AND b.rownum = a.rownum + 1
AND a.location <> b.location
A variant of this subquery, where you say SELECT b.*, gets the rows right after a change in location (http://sqlfiddle.com/#!9/6c3bc7/3/0)
Finally, you take the setwise UNION of those two queries, order it appropriately, and you have your set of rows with the duplicate consecutive positions removed. Please notice that this gets quite verbose in MySQL because the nasty #rowa := #rowa + 1 hack used to generate row numbers has to use a different variable (#rowa, #rowb, etc) in each copy of the subquery. (http://sqlfiddle.com/#!9/6c3bc7/4/0)
SELECT a.*
FROM (
SELECT (#rowa := #rowa + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowa := 0) init
ORDER BY VEHICLE, TIME
) a
JOIN (
SELECT (#rowb := #rowb + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowb := 0) init
ORDER BY VEHICLE, TIME
) b ON a.VEHICLE = b.VEHICLE AND b.rownum = a.rownum + 1 AND a.location <> b.location
UNION
SELECT d.*
FROM (
SELECT (#rowc := #rowc + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowc := 0) init
ORDER BY VEHICLE, TIME
) c
JOIN (
SELECT (#rowd := #rowd + 1) rownum,
loc.*
FROM loc
JOIN (SELECT #rowd := 0) init
ORDER BY VEHICLE, TIME
) d ON c.VEHICLE = d.VEHICLE AND c.rownum = d.rownum - 1 AND c.location <> d.location
order by VEHICLE, TIME
And, in next-generation MySQL, available in beta now in MariaDB 10.2, this is much much easier. The new generation as common table expressions and row numbering.
with loc as
(
SELECT ROW_NUMBER() OVER (PARTITION BY VEHICLE ORDER BY time) rownum,
loc.*
FROM loc
)
select a.*
from loc a
join loc b ON a.VEHICLE = b.VEHICLE
AND b.rownum = a.rownum + 1
AND a.location <> b.location
union
select b.*
from loc a
join loc b ON a.VEHICLE = b.VEHICLE
AND b.rownum = a.rownum + 1
AND a.location <> b.location
order by vehicle, time

MySQL math to get Top 3 scores

I'm doing a website for a Fantasy Movie League and what I'm trying to do is get the Top 3 Total Scores overall
Total scores should be: The sum of various points for each players's active movies DIVIDED BY the number of that player's active movies
(So if a player has 300 points from active movies and has 3 active movies, the answer should be 100)
So my question is: How do I calculate the individual player's number of active movies (in the subquery) without specifying the player_id?
SELECT
players.id as player_id,
first_name, last_name,
(metacritic + (imdb*10) + top_bottom + power(receipts,(2/9)) + ticket + oscar_noms + oscar_wins + gg_noms + gg_wins + isa_noms + isa_wins + razzie_noms + razzie_wins + festival_points + ifca_points) / (SELECT COUNT(id) FROM movies WHERE release_date >= CURDATE() and year_id=1 and player_id=4) as player_active_movie_total
FROM movies
INNER JOIN players on players.id=movies.player_id
WHERE release_date >= CURDATE() and year_id=1
ORDER BY player_active_movie_total DESC
LIMIT 3
You don't need a subQuery in your select statement. Based on your criteria you just need to use a GROUP BY statement and a COUNT on ID. The query below will NOT work because you need grouping/sum on each column, but should point you in the right direction
SELECT players.id as player_id, first_name, last_name,
(metacritic + (imdb*10) + top_bottom + power(receipts,(2/9)) + ticket + oscar_noms + oscar_wins + gg_noms + gg_wins + isa_noms + isa_wins + razzie_noms + razzie_wins + festival_points + ifca_points) /
(COUNT(id)) as player_active_movie_total
FROM movies
INNER JOIN players on players.id=movies.player_id
WHERE release_date >= CURDATE() and year_id=1
GROUP BY players.id, first_name, last_name
ORDER BY player_active_movie_total DESC
LIMIT 3
Your metacritic column (and all other in the SELECT list) either need to be part of an aggregate function i.e. SUM or COUNT or MAX or listed in the GROUP BY statement like players.id is. I'm assuming you're wanting some sort of SUM on that entire column

MySQL count occurrences greater than 2

I have the following table structure
+ id + word +
+------+--------+
The table gets filled with the words in lower cas of a given text, so the text
Hello bye hello
would result in
+ id + word +
+------+--------+
+ 1 + hello +
+------+--------+
+ 2 + bye +
+------+--------+
+ 3 + hello +
+------+--------+
I want to make a SELECT query that will return the number of words that get repeated at least two times in the table (like hello)
SELECT COUNT(id) FROM words WHERE (SELECT COUNT(words.word))>1
which of course is so wrong and super overloading when table is big. Any idea on how to achieve such purpose? In the given example inhere-above, I would expect 1
To get a list of the words that appear more than once together with how often they occur, use a combination of GROUP BY and HAVING:
SELECT word, COUNT(*) AS cnt
FROM words
GROUP BY word
HAVING cnt > 1
To find the number of words in the above result set, use that as a subquery and count the rows in an outer query:
SELECT COUNT(*)
FROM
(
SELECT NULL
FROM words
GROUP BY word
HAVING COUNT(*) > 1
) T1
SELECT count(word) as count
FROM words
GROUP BY word
HAVING count >= 2;
SELECT word, COUNT(*) FROM words GROUP by word HAVING COUNT(*) > 1
The HAVING option can be used for this purpose and query should be
SELECT word, COUNT(*) FROM words
GROUP BY word
HAVING COUNT(*) > 1;