Sql Server 2008 R2
I have this data:
Id AdOrderId AdRunScheduleId CategoryCode EffectiveDate Amount
735935 3811 1629 0 3/7/14 0:00 72.19
735939 3811 1629 2 3/7/14 0:00 10
735942 3811 1629 7 3/7/14 0:00 -14.44
I would like a view that contains 1 row with all 3 records
I have tried several things. Several work but all give me 3 separate rows.
Here is my latest attempt:
-CREATE View [dbo].[DP_AdOrder_Charges]
--as
SELECT
Elem.Id,
Elem.AdOrderId, Elem.AdRunScheduleId, Elem.EffectiveDate,
Elem.Amount, Elem.CategoryCode,
MAX(Case when Elem.CategoryCode = 0 then Elem.Amount End) as AdInsertAmt,
MAX(Case when Elem.CategoryCode = 2 then Elem.Amount End) as ColorAmt,
MAX(Case when Elem.CategoryCode = 7 then Elem.Amount End) as DiscAmt,
MAX(Case when Elem.CategoryCode not in (0,2,7) then Elem.Amount End) as OtherAmt
FROM [MNADTEST].[dbo].[RtChargeEntryElem] Elem
INNER JOIN [MNADTEST].[dbo].[RtChargeEntryElem] J1
ON Elem.EffectiveDate=J1.EffectiveDate
and Elem.Id=J1.Id
and Elem.AdRunScheduleId=J1.AdRunScheduleId
and Elem.AdOrderId=J1.AdOrderId
Where Elem.AdRunScheduleId=1629
and Elem.EffectiveDate='2014-03-07'
GROUP BY
Elem.Id,Elem.EffectiveDate,
Elem.AdOrderId, Elem.AdRunScheduleId,
Elem.Amount, Elem.RateTableId, Elem.CategoryCode
with this result
Id AdOrderId AdRun Effective Amount Category AdInsertAmt ColorAmt DiscAmt OtherAmt
ScheduleId Date Code
735935 3811 1629 2014-03-07 72.19 0 72.19 NULL NULL NULL
735939 3811 1629 2014-03-07 10 2 NULL 10 NULL NULL
735942 3811 1629 2014-03-07 -14.44 7 NULL NULL -14.44 NULL
I would be grateful for any help.
thanks.
Barb
Here is create table and insert code:
CREATE TABLE [dbo].[RtChg](
[Id] [int] NOT NULL,
[AdOrderId] [int] NULL,
[AdRunScheduleId] [int] NULL,
[CategoryCode] [int] NULL,
[EffectiveDate] [datetime] NULL,
[Amount] [float] NULL
)
GO
INSERT INTO [dbo].[RtChg]
([Id],
[AdOrderId],
[AdRunScheduleId],
[CategoryCode],
[EffectiveDate],
[Amount])
VALUES
(735935, 3811, 1629, 0, '3/7/14', '72.19'),
(735939 ,3811, 1629, 2, '3/7/14', '10.00'),
(735942, 3811, 1629, 7, '3/7/14', '-14.44')
GO
I have this working. I did not need a self join. Also, I was grouping by a unique id instead of the column I want to capture when the value changes.
CREATE View [dbo].[DP_AdOrder_Charges]
as
SELECT
AdOrderId,
Elem.AdRunScheduleId,
Elem.EffectiveDate,
MAX(Case when Elem.CategoryCode = 0 then Elem.Amount End) as AdInsertAmt,
MAX(Case when Elem.CategoryCode = 2 then Elem.Amount End) as ColorAmt,
MAX(Case when Elem.CategoryCode = 7 then Elem.Amount End) as DiscAmt,
MAX(Case when Elem.CategoryCode not in (0,2,7) then Elem.Amount End) as OtherAmt
FROM [MNADTEST].[dbo].[RtChargeEntryElem] Elem
GROUP BY
Elem.AdOrderId,
Elem.AdRunScheduleId,
Elem.EffectiveDate
Related
SELECT
COUNT(CASE WHEN VALUE = 1 THEN 1 END) AS score_1,
COUNT(CASE WHEN VALUE = 2 THEN 1 END) AS score_2,
COUNT(CASE WHEN VALUE = 3 THEN 1 END) AS score_3,
COUNT(CASE WHEN VALUE = 4 THEN 1 END) AS score_4,
COUNT(CASE WHEN VALUE = 5 THEN 1 END) AS score_5,
COUNT(CASE WHEN VALUE = 6 THEN 1 END) AS score_6,
COUNT(CASE WHEN VALUE = 7 THEN 1 END) AS score_7,
COUNT(CASE WHEN VALUE = 8 THEN 1 END) AS score_8,
COUNT(CASE WHEN VALUE = 9 THEN 1 END) AS score_9,
COUNT(CASE WHEN VALUE = 10 THEN 1 END) AS score_10
FROM
`answers`
WHERE
`created_at` BETWEEN '2017-01-01 00:00:00' AND '2019-11-30 23:59:59'
Is there a way to optimize this query, because I have 4 million answer records in my DB, and it runs very slowly?
Try running this one time to create an index:
CREATE INDEX ix_ca on answers(created_at)
That should speed your query up. If you are curious about why, see here:
What is an index in SQL?
You could try add a redundant composite index
create idx1 on table answers(created_at, value)
using redudance in index the query should be result without accessing to table data just using the index content
Want it to be 10 times as fast? Use the Data Warehousing technique of buiding and maintaining a "Summary table". In this example the summary table might be
CREATE TABLE subtotals (
dy DATE NOT NULL,
`value` ... NOT NULL, -- TINYINT UNSIGNED ?
ct SMALLINT UNSIGNED NOT NULL, -- this is 2 bytes, max 65K; change if might be bigger
PRIMARY KEY(value, dy) -- or perhaps the opposite order
) ENGINE=InnoDB
Each night you summarize the day's data and build 10 new rows in subtotals.
Then the "report" query becomes
SELECT
SUM(CASE WHEN VALUE = 1 THEN ct END) AS score_1,
SUM(CASE WHEN VALUE = 2 THEN ct END) AS score_2,
SUM(CASE WHEN VALUE = 3 THEN ct END) AS score_3,
SUM(CASE WHEN VALUE = 4 THEN ct END) AS score_4,
SUM(CASE WHEN VALUE = 5 THEN ct END) AS score_5,
SUM(CASE WHEN VALUE = 6 THEN ct END) AS score_6,
SUM(CASE WHEN VALUE = 7 THEN ct END) AS score_7,
SUM(CASE WHEN VALUE = 8 THEN ct END) AS score_8,
SUM(CASE WHEN VALUE = 9 THEN ct END) AS score_9,
SUM(CASE WHEN VALUE = 10 THEN ct END) AS score_10
FROM
`subtotals`
WHERE `created_at` >= '2017-01-01'
AND `created_at` < '2019-12-01'
Based on what you have provided, there will be about 10K rows in subtotals; that's a lot less to wade through than 4M rows. It might run more than 10 times as fast.
More discussion: http://mysql.rjweb.org/doc.php/summarytables
I have a table which stores application details. Applications are nothing but a set of data showing scores.
Each application has 6 parts namely 1,2,3,4,5, and 6. So, in the database table parts can have values ranging from 1 to 6.
Same application can have one or more entries saved for a part. Like, application with id 9 can have (may be) 3 entries for part 1. and for each part there is a score and score is just a numeric value.
What I'm trying to fetch is: Get scores for all 6 parts for each application but only the most recent score should be shown. So, if application 9 part 1 has a score of 8 at 01-06-2016 and the same has a score of 3 on 03-06-2016, then 3 should be shown as the score.
My table looks like this:
CREATE TABLE IF NOT EXISTS `reg_updates` (
`id` int(11) NOT NULL,
`application_id` int(11) NOT NULL,
`part` int(11) NOT NULL,
`reg_score_id` int(11) NOT NULL,
`reg_score` int(11) NOT NULL,
`done_date` date NOT NULL,
`done_time` time NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=latin1;
And this is the query that I have written for this purpose:
SELECT MAX(CONCAT(RU.done_date,' ',RU.done_time)) AS date,RU.application_id,
MAX(CASE WHEN (RU.part = 1 ) THEN RU.reg_score END) part1Score,
MAX(CASE WHEN RU.part = 2 THEN RU.reg_score END) part2Score,
MAX(CASE WHEN RU.part = 3 THEN RU.reg_score END) part3Score,
MAX(CASE WHEN RU.part = 4 THEN RU.reg_score END) part4Score,
MAX(CASE WHEN RU.part = 5 THEN RU.reg_score END) part5Score,
MAX(CASE WHEN RU.part = 6 THEN RU.reg_score END) part6Score
FROM reg_updates AS RU
GROUP BY RU.application_id;
But it's not fetching the proper data. I am not able to get the data based on latest done_date and done_time. I'm only getting it based on the first entry.
This is the tutorial link I followed to create this kinda pivot table.
Here's a sample SQL FIDDLE.
Well, you should first get all data with most recent datetime by application_Id and part, which will be used as an inner join
SELECT MAX(CONCAT(done_date,' ',done_time)) AS maxDate ,application_id,RU.part
FROM reg_updates
GROUP BY application_id, part;
Then use it in your query
SELECT
-- I'm not sure you want that line, do you ? It will only retrieve the latest date_time of ALL your parts for that application
MAX(CONCAT(RU.done_date,' ',RU.done_time)) AS date,
RU.application_id,
MAX(CASE WHEN (RU.part = 1 ) THEN RU.reg_score END) part1Score,
MAX(CASE WHEN RU.part = 2 THEN RU.reg_score END) part2Score,
MAX(CASE WHEN RU.part = 3 THEN RU.reg_score END) part3Score,
MAX(CASE WHEN RU.part = 4 THEN RU.reg_score END) part4Score,
MAX(CASE WHEN RU.part = 5 THEN RU.reg_score END) part5Score,
MAX(CASE WHEN RU.part = 6 THEN RU.reg_score END) part6Score
FROM reg_updates AS RU
--now you join on the previous
join (SELECT MAX(CONCAT(done_date,' ',done_time)) AS maxDate ,application_id,part
FROM reg_updates
GROUP BY application_id, part) maxValues
on maxValues.part = RU.part and
maxValues.application_Id = RU.application_id and
maxValues.maxDate = CONCAT(RU.done_date,' ',RU.done_time)
GROUP BY RU.application_id;
By the way, you will only get the latest date_time of all the part, but it seems that it's what you want ?
Looking for the way to change row to column. (The comflag is of type bit and not null). Help appreciated
Table1
Id Commflag value
122 0 Ce
125 1 Cf
122 0 Cg
125 1 cs
Here is what I want in result
id ce cf cg cs cp
122 0 null 0 null null
125 null 1 null 1 null
The below query shows error-
SELECT ID , [CE],[CF],[CG],[CS],[CP]
FROM TABLE1
PIVOT ((convert((Commflag)as varchar()) FOR value IN [CE],[CF],[CG],[CS],[CP] as pvt
ORDER BY date
This query does what you want:
select Id, pvt.Ce, pvt.Cf, pvt.CG, pvt.Cs, pvt.Cp
from
(
select Id, cast(Commflag as tinyint) Commflag, value
from Table1
) t
pivot (max(Commflag) for value in ([Ce],[Cf],[CG],[Cs],[Cp])) pvt
SQL Fiddle
Here's another way to do it, without using PIVOT:
select Id,
max(case value when 'Ce' then CAST(Commflag as tinyint) else null end) Ce,
max(case value when 'Cf' then CAST(Commflag as tinyint) else null end) Cf,
max(case value when 'Cg' then CAST(Commflag as tinyint) else null end) Cg,
max(case value when 'Cs' then CAST(Commflag as tinyint) else null end) Cs,
max(case value when 'Cp' then CAST(Commflag as tinyint) else null end) Cp
from Table1
group by Id
order by Id
SQL Fiddle
I have an analytics table (5M rows and growing) with the following structure
Hits
id int() NOT NULL AUTO_INCREMENT,
hit_date datetime NOT NULL,
hit_day int(11) DEFAULT NULL,
gender varchar(255) DEFAULT NULL,
age_range_id int(11) DEFAULT NULL,
klout_range_id int(11) DEFAULT NULL,
frequency int(11) DEFAULT NULL,
count int(11) DEFAULT NULL,
location_id int(11) DEFAULT NULL,
source_id int(11) DEFAULT NULL,
target_id int(11) DEFAULT NULL,
Most queries to the table is to query between two datetimes for a particular sub-set of columns and them sum up all the count column across all rows. For example:
SELECT target.id,
SUM(CASE gender WHEN 'm' THEN count END) AS 'gender_male',
SUM(CASE gender WHEN 'f' THEN count END) AS 'gender_female',
SUM(CASE age_range_id WHEN 1 THEN count END) AS 'age_18 - 20',
SUM(CASE target_id WHEN 1 then count END) AS 'target_test'
SUM(CASE location_id WHEN 1 then count END) AS 'location_NY'
FROM Hits
WHERE (location_id =1 or location_id = 2)
AND (target_id = 40 OR target_id = 22)
AND cast(hit_date AS date) BETWEEN '2012-5-4'AND '2012-5-10'
GROUP BY target.id
The interesting thing about queries to this table is that the where clause include any permutation of Hit columns names and values since those are what we're filtering against. So the particular query above is getting the # of males and females between the ages of 18 and 20 (age_range_id 1) in NY that belongs to a target called "test". However, there are over 8 age groups, 10 klout ranges, 45 locations, 10 sources etc (all
foreign key references).
I currently have an index on hot_date and another one on target_id. What the best way to properly index this table?. Having a composite index on all column fields seems inherently wrong.
Is there any other way to run this query without using a sub-query to sum up all counts? I did some research and this seems to be the best way to get the data-set I need but is there a more efficient way of handling this query?
Here's your optimized query. The idea is to get rid of the ORs and the CAST() function on hit_date so that MySQL can utilize a compound index that covers each of the subsets of data. You'll want a compound index on (location_id, target_id, hit_date) in that order.
SELECT id, gender_male, gender_female, `age_18 - 20`, target_test, location_NY
FROM
(
SELECT target.id,
SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male,
SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female,
SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`,
SUM(CASE target_id WHEN 1 then 1 END) AS target_test,
SUM(CASE location_id WHEN 1 then 1 END) AS location_NY
FROM Hits
WHERE (location_id =1)
AND (target_id = 40)
AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59'
GROUP BY target.id
UNION ALL
SELECT target.id,
SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male,
SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female,
SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`,
SUM(CASE target_id WHEN 1 then 1 END) AS target_test,
SUM(CASE location_id WHEN 1 then 1 END) AS location_NY
FROM Hits
WHERE (location_id = 2)
AND (target_id = 22)
AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59'
GROUP BY target.id
UNION ALL
SELECT target.id,
SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male,
SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female,
SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`,
SUM(CASE target_id WHEN 1 then 1 END) AS target_test,
SUM(CASE location_id WHEN 1 then 1 END) AS location_NY
FROM Hits
WHERE (location_id =1)
AND (target_id = 22)
AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59'
GROUP BY target.id
UNION ALL
SELECT target.id,
SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male,
SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female,
SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`,
SUM(CASE target_id WHEN 1 then 1 END) AS target_test,
SUM(CASE location_id WHEN 1 then 1 END) AS location_NY
FROM Hits
WHERE (location_id = 2)
AND (target_id = 22)
AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59'
GROUP BY target.id
) a
GROUP BY id
If your selection size is so large that this is no improvement, then you may as well keep scanning all rows like you're already doing.
Note, surround aliases with back ticks, not single quotes, which are deprecated. I also fixed your CASE clauses which had count instead of 1.
How do I get the sum of each column for all rows of a result-set? I mean I want to display the sums-row as the last row of my result-set.
My query looks like this:
select f.filename,
count(distinct case when v.rUser like '%bike%' then 1 else null end) as bikeUser,
count(distinct case when v.rUser like '%Pedestrian%' then 1 else null end) as pedestrianUser,
count(distinct case when d.weather like '%clear%' then 1 else null end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else null end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
When I use with roll up after the 'group by' clause, it gives me sum of the groups generated by the 'group by clause' (horizontal sum) whereas I need the vertical sum of each column at the end.
Any ideas?
Your ROLLUP is already correct, it's really the COUNT(CASE WHEN Field = 'Blah' THEN 1 ELSE 0 END) is the main culprit why your query is not working
You must do either:
COUNT(CASE WHEN Field = 'Blah' THEN 1 END)
or
SUM(CASE WHEN Field = 'Blah' THEN 1 ELSE 0 END)
But since MySQL has a duality between boolean and integer type like it is in C language, hence you can do this too:
SUM(Field = 'Blah')
This is your incorrect query (wrong results): http://www.sqlfiddle.com/#!2/70187/1
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','CN');
insert into ProductInventory(ProductCode,Location) values('KB','CN');
insert into ProductInventory(ProductCode,Location) values('KB','JP');
insert into ProductInventory(ProductCode,Location) values('KB','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','CN');
Incorrect Output:
PRODUCTCODE USQTY CHINAQTY
CPU 3 3
KB 3 3
MOUSE 2 2
8 8
This is the correct query: http://www.sqlfiddle.com/#!2/70187/2
select ProductCode,
COUNT(CASE WHEN Location = 'US' THEN 1 END) as UsQty,
COUNT(CASE WHEN Location = 'CN' THEN 1 END) as ChinaQty
from ProductInventory
group by ProductCode with rollup
Correct output:
PRODUCTCODE USQTY CHINAQTY
CPU 2 1
KB 1 1
MOUSE 1 1
4 3
Please, don't insist that this is correct, this is very incorrect:
COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) AS UsQty
You must either do this (correct) :
COUNT(CASE WHEN Location = 'US' THEN 1 END) AS UsQty
Or this (correct) : http://www.sqlfiddle.com/#!2/70187/5
SUM(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) AS UsQty
Or this (correct) : http://www.sqlfiddle.com/#!2/70187/6
SUM(CASE WHEN Location = 'US' THEN 1 END) AS UsQty
Or try take advantage of the fact that MySql has duality between boolean and integer (correct) : http://www.sqlfiddle.com/#!2/70187/4
SUM(Location = 'US') AS UsQty
Bottomline
Please don't use this (incorrect) : http://www.sqlfiddle.com/#!2/70187/3
COUNT(Location = 'US') as UsQty
And please don't use this too (incorrect, similar to your query): http://www.sqlfiddle.com/#!2/70187/1
COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) as UsQty
By the way, this also works, it's for you to find out why ;-)
COUNT(CASE WHEN Location = 'US' THEN 1976 END) AS UsQty
UPDATE
I have an inkling that this is what you need:
create table Product
(
ProductCode varchar(10) not null primary key,
ProductName varchar(100) not null
);
insert into Product(ProductCode,ProductName) values
('CPU','Central Processing Unit'),
('KB','Keyboard'),
('MSE','Mouse'),
('RAM', 'Random Access Memory');
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values
('CPU','US'),
('CPU','PH'),
('CPU','PH'),
('KB','PH'),
('KB','US'),
('KB','US'),
('MSE','US'),
('MSE','JP');
select p.ProductCode,
coalesce(SUM(i.Location = 'US'),0) as UsQty,
coalesce(SUM(i.Location = 'PH'),0) as PhilippinesQty
from Product p
left join ProductInventory i on i.ProductCode = p.ProductCode
group by p.ProductCode with rollup
Output:
ProductCode UsQty PhilippinesQty
CPU 1 2
KB 2 1
MSE 1 0
RAM 0 0
4 4
Live test: http://www.sqlfiddle.com/#!2/2bb09/1
Don't use COUNT for counting when you are using evaluation; despite the name, SUM would yield the correct result for counting based on conditions:
Given this: http://www.sqlfiddle.com/#!2/79375/1
create table ProductInventory(
ProductCode varchar(10) not null,
Location varchar(50) not null
);
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','US');
insert into ProductInventory(ProductCode,Location) values('CPU','ARM');
insert into ProductInventory(ProductCode,Location) values('KB','CN');
insert into ProductInventory(ProductCode,Location) values('KB','PH');
insert into ProductInventory(ProductCode,Location) values('KB','US');
insert into ProductInventory(ProductCode,Location) values('MOUSE','AA');
insert into ProductInventory(ProductCode,Location) values('MOUSE','BB');
select ProductCode, COUNT(CASE WHEN Location = 'US' THEN 1 ELSE 0 END) as Qty
from ProductInventory
group by ProductCode
order by ProductCode
That will produce incorrect results:
PRODUCTCODE QTY
CPU 3
KB 3
MOUSE 2
Use SUM instead, correct results: http://www.sqlfiddle.com/#!2/79375/3
select ProductCode, SUM(Location = 'US') as Qty
from ProductInventory
group by ProductCode
order by ProductCode
That would result to:
PRODUCTCODE QTY
CPU 2
KB 1
MOUSE 0
COUNT works by counting the NON-nullness of value or expression
If you still want to use COUNT, pass any non-null value to COUNT; and don't use ELSE NULL END, your query will look tedious, just saying :-) http://www.sqlfiddle.com/#!2/79375/4
select ProductCode, COUNT(CASE WHEN Location = 'US' THEN Location END) as Qty
from ProductInventory
group by ProductCode
order by ProductCode
Output:
PRODUCTCODE QTY
CPU 2
KB 1
MOUSE 0
You can create a temptable (#mytemptable) and add the sum as last entry and then return the select of the created temptable. But this is only working in stored procedures I think.
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
INTO #myTempTable from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
INSERT INTO #myTempTable select(create the sum here but care that you have the same columns)
SELECT * FROM #myTempTable
within just one select you can do it with the command "UNION"
*EDITED: 27.04. 11:55
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename;
UNION
SELECT SUM(bikeUser), SUM(pedestrianUser), SUM(clearWeather), SUM(hatExtras)
FROM (
select f.filename,
count(case when v.rUser like '%bike%' then 1 else 0 end) as bikeUser,
count(case when v.rUser like '%Pedestrian%' then 1 else 0 end) as pedestrianUser,
count(case when d.weather like '%clear%' then 1 else 0 end) as clearWeather,
count(case when m.extras like '%hat%' then 1 else 0 end) as hatExtras
from VMdata v
inner join files f on v.id = f.id
inner join DMdata d on f.id = d.id
inner join MultiFiledata m on f.id = m.id
where f.filename in (X,Y,Z) group by f.filename) as summary
hope this helps :)