Get Multi Columns Count in Single Query - mysql

I am working on a application where I need to write a query on a table, which will return multiple columns count in a single query.
After research I was able to develop a query for a single sourceId, but what will happen if i want result for multiple sourceIds.
select '3'as sourceId,
(select count(*) from event where sourceId = 3 and plateCategoryId = 3) as TotalNewCount,
(select count(*) from event where sourceId = 3 and plateCategoryId = 4) as TotalOldCount;
I need to get TotalNewCount and TotalOldCount for several source Ids, for example (3,4,5,6)
Can anyone help, how can I revise my query to return a result set of three columns including data of all sources in list (3,4,5,6)
Thanks

You can do all source ids at once:
select source_id
sum(case when plateCategoryId = 3 then 1 else 0 end) as TotalNewCount,
sum(case when plateCategoryId = 4 then 1 else 0 end) as TotalOldCount
from event
group by source_id;
Use a where (before the group by) if you want to limit the source ids.
Note: The above works in both Vertica and MySQL, and being standard SQL should work in any database.

Related

To get total count based on condition

I am struggling to get the count of a particular person. As I am new to tableau I don't know how to write the condition for this query.
SELECT COUNT(*) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 AND
IsAccepted = 1
Generate a calculated field as:
Calculation1: IF ExpertID=3 AND IsAccepted = 1 THEN 1 ELSE 0 END
Then, place this field on a shelf (row, columns, etc.) and select Measure (Sum).
You can use LOD (Level of Detail) like so:
{ FIXED [ExpertID]: SUM(IF [IsAccepted]= 1 THEN 1 ELSE 0 END) }
This will give you aggregated values for each user.
For more information on LOD, please follow official Tableau help link here
SELECT COUNT(ExpertID),COUNT(IsAccepted ) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 OR
IsAccepted = 1

SQL avg of comma occurrencies with condition

I have a table of events where partecipants are listed as a comma separated list of IDs:
0,4,21,33,41
I'm trying to perform the following query to retrieve the average partecipants number for event only when status is equal to 1.
I prepared the following but doesn't work, anyone can help me?
SELECT avg(case when (status = 1 then LENGTH(REPLACE(listofPartecipants, ',', '')) end) avgPartecipants FROM events;
Many thanks
This is the expression if you want to count the number of elements in a list:
SELECT avg(case when status = 1
then LENGTH(REPLACE(listofPartecipants, ',', 'XX')) - length(listofPartecipants) + 1
end) as avgPartecipants
FROM events;
More important than getting this arcane string logic right is fixing your data model. You should not be storing list of ids in a comma-delimited list. You should have a table with one row per event and per participant.

why my sql query slow?

I try to create a view which join from 4 tables (tb_user is 200 row, tb_transaction is 250.000 row, tb_transaction_detail is 250.000 row, tb_ms_location is 50 row),
when i render with datatables serverside, it's take 13 secons. even when I filtering it.
I don't know why it's take too long...
here my sql query
CREATE VIEW `vw_cashback` AS
SELECT
`tb_user`.`nik` AS `nik`,
`tb_user`.`full_name` AS `nama`,
`tb_ms_location`.`location_name` AS `lokasi`,
`tb_transaction`.`date_transaction` AS `tanggal_setor`,
sum(CASE WHEN `tb_transaction_detail`.`vehicle_type`=1 THEN 1 ELSE 0 END) AS `mobil`,
sum(CASE WHEN `tb_transaction_detail`.`vehicle_type`=2 THEN 1 ELSE 0 END) AS `motor`,
sum(CASE WHEN `tb_transaction_detail`.`vehicle_type`=3 THEN 1 ELSE 0 END) AS `truck`,
sum(CASE WHEN `tb_transaction_detail`.`vehicle_type`=4 THEN 1 ELSE 0 END) AS `speda`,
sum(`tb_transaction_detail`.`total`) AS `total_global`,
(sum(`tb_transaction_detail`.`total`) * 0.8) AS `total_user`,
(sum(`tb_transaction_detail`.`total`) * 0.2) AS `total_tgr`,
((sum(`tb_transaction_detail`.`total`) * 0.2) / 2) AS `total_cashback`,
(curdate() - cast(`tb_user`.`created_at` AS date)) AS `status`
FROM `tb_user`
JOIN `tb_transaction` ON `tb_user`.`id` = `tb_transaction`.`user_id`
JOIN `tb_transaction_detail` ON `tb_transaction`.`id` = `tb_transaction_detail`.`transaction_id`
JOIN `tb_ms_location` ON `tb_ms_location`.`id` = `tb_transaction`.`location_id`
GROUP BY
`tb_user`.`id`,
`tb_transaction`.`date_transaction`,
`tb_user`.`nik`,
`tb_user`.`full_name`,
`tb_user`.`created_at`,
`tb_ms_location`.`location_name`
thanks
The unfiltered query must be slow, because it takes all records from all tables, joins and aggregates them.
But you say the view is still slow when you filter. The question is: How do you filter? As you are aggregating by user, location and transaction date, it should be one of these. However, you don't have the user ID or the transaction ID in your result list. This doesn't feel natural and I'd suggest you add them, so a query like
select * from vw_cashback where user_id = 5
or
select * from vw_cashback where transaction_id = 12345
would be possible.
As is, you'd have to filter by location name or user nik / name. So if you want it thus, then create Indexes for the lookup:
CREATE idx_location_name ON tb_ms_location(location_name, id)
CREATE idx_user_name ON tb_user(full_name, id)
CREATE idx_user_nik ON tb_user(nik, id)
The latter two can even be turned into covering indexs (i.e. indexes containing all columns used in the query) that may still speed up the process:
CREATE idx_user_name ON tb_user(nik, id, full_name, created_at);
CREATE idx_user_nik ON tb_user(full_name, id, nik, created_at);
As for the access via index, you also may want covering indexes:
CREATE idx_location_id ON tb_ms_location(id, location_name)
CREATE idx_user_id ON tb_user(id, nik, full_name, created_at);

Rails 4 get column names in raw activerecord query

I have some code that looks like the following:
query = <<-EOF
select player_id, first_name, last_name,
max(case when site_id = 1 then salary end) fd_salary,
max(case when site_id = 2 then salary end) dd_salary,
max(case when site_id = 3 then salary end) ss_salary,
max(case when site_id = 4 then salary end) ds_salary,
max(case when site_id = 7 then salary end) dk_salary,
max(case when site_id = 8 then salary end) elite_salary
from player_salaries ps
where ps.gamedate = '2014-05-25'
and sport_id = #{$MLB_SPORT_ID}
group by player_id
EOF
salaries = PlayerSalary.connection.execute(query)
The problem is salaries in this case comes back as an array with values. These query is a bit complex and the names I'm using such as fd_salary, dd_salary and so forth aren't physical attributes in the PlayerSalary model. There's no way to do something like salaries.first.fd_salary. Is there a way to change the above in Rails 4 to get it access values by column name?
You could use find_by_sql for this:
find_by_sql(sql, binds = [])
Executes a custom SQL query against your database and returns all the results. The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from. If you call Product.find_by_sql then the results will be returned in a Product object with the attributes you specified in the SQL query.
So if you did:
salaries = PlayerSalary.find_by_sql(query)
then you could say things like salaries.first.fd_salary. Just don't try to use columns that weren't in your query or try to change the returned PlayerSalary objects and expect anything useful to happen.
If you want to retrieve your records as a hash, with column names you can use mysql2 adapter directly with:
ActiveRecord::Base.connection.instance_variable_get('#connection').query("SELECT * FROM `users`", as: :hash).first
I was searching for another way to do it but had no luck.

MYSQL retrieve data dependent on rows returned

I am working on a mysql query that will filter out certain occurrences dependent on how many rows are returned.
I am trying to filter out any support categories when the number of rows returned are 1, however leave the support category in when the result set turned is more than 1.
I originally had this idea however it seems as if it will not work.
SELECT stockmaster.description, SUM(salesorderdetails.quantity), stockmaster.categoryid as qty
FROM salesorderdetails, stockmaster
where salesorderdetails.stkcode=stockmaster.stockid
and orderno='5222'
group by stockmaster.description
HAVING CASE WHEN stockmaster.categoryid = 'S&M' THEN COUNT(*) >= 2 ELSE COUNT(*) = 1 END
Any help will be gratefully accepted.
Try this
SELECT *
FROM
(
SELECT stockmaster.description,
SUM(salesorderdetails.quantity),
stockmaster.categoryid as qty ,
COUNT(*) AS count
FROM salesorderdetails, stockmaster
where salesorderdetails.stkcode=stockmaster.stockid
and orderno='5222'
group by stockmaster.description
HAVING CASE WHEN stockmaster.categoryid = 'S&M'
) MAIN_DATA
WHERE MAIN_DATA.count >1