Right now I have the following query:
SELECT
rm.reward_name,
rm.rewardid,
rc.reward_code,
rc.status,
rc.rewardid,
rc.add_date,
rc.status
from rewards_codes as rc
INNER JOIN reward_mast as rm on rc.rewardid on rm.rewardid
where DATE(rc.add_date) between '2012-03-16' AND '2013-03-16';
I want to fetch total no of codes,available codes from all codes,used codes
i have taken status field in rewards_codes field for differentiate code status
0 - Available to use
1- Used code
So my final output should be like following:
-----------------------------------------------------------
Reward Name Total Codes Available code Used code
my_reward 100 40 60
extra_reward 100 90 10
-----------------------------------------------------------
[Update]
Here is some sample data from both table...
reward_mast
rewardid rewrd_name
1 my_reward
2 extra_reward
3 test_reward
rewards_codes
codeId rewardid reward_code add_date status
1 1 aka454 2012-11-21 0
2 2 ala499 2012-04-21 0
3 1 pao789 2012-08-21 0
4 3 zlk753 2012-01-21 0
5 2 qra954 2012-05-21 0
Try this:
SELECT
rm.rewardid,
rm.reward_name,
IFNULL(COUNT(rc.reward_code), 0) AS 'Total Codes',
IFNULL(SUM(rc.status = 0), 0) AS 'Available code',
IFNULL(SUM(rc.status = 1), 0) AS 'Used Codes'
FROM reward_mast as rm
LEFT JOIN rewards_codes as rc on rc.rewardid = rm.rewardid
WHERE DATE(rc.add_date) between '2012-03-16' AND '2013-03-16'
GROUP BY rm.reward_name,
rm.rewardid;
This will give you the count of each category of status codes individually, Totalcodes, Available Codes and Used Codes.
SQL Fiddle Demo
This will give you:
| REWARDID | REWARD_NAME | TOTAL CODES | AVAILABLE CODE | USED CODES |
-----------------------------------------------------------------------
| 1 | my_reward | 2 | 2 | 0 |
| 2 | extra_reward | 2 | 2 | 0 |
Related
I count my data from database, but I have a problem with the result. the result only displays data that is not empty, while the empty data is not displayed. how do I display data rows that are empty and not empty?
the result of my query like this
pendidikan| Male | Famale | Total
----------+------+--------+------
SD | 3 | 4 | 7
SMP | 2 | 1 | 3
SMA | 1 | 3 | 4
S1 | 10 | 1 | 11
BUT i want the result like this :
pendidikan| Male | Famale | Total
----------+------+--------+------
SD | 3 | 4 | 7
SMP | 2 | 1 | 3
SMA | 1 | 3 | 4
S1 | 10 | 1 | 11
S2 | 0 | 0 | 0
S3 | 0 | 0 | 0
i want to show empty data from my database. this is my query
SELECT a.NamaStatusPendidikan, COUNT(c.IDPencaker) as total,
count(case when c.JenisKelamin='0' then 1 end) as laki,
count(case when c.JenisKelamin='1' then 1 end) as cewe
FROM msstatuspendidikan as a JOIN mspencaker as c ON
a.IDStatusPendidikan = c.IDStatusPendidikan JOIN
mspengalaman as d ON c.IDPencaker = d.IDPencaker
WHERE d.StatusPekerjaan = '0' AND c.RegisterDate
BETWEEN '2019-01-01' AND '2019-03-01' GROUP BY a.IDStatusPendidikan
Try running this query:
SELECT sp.NamaStatusPendidikan,
COUNT(*) as total,
SUM( p.JenisKelamin = 0 ) as laki,
SUM( p.JenisKelamin = 1 ) as cewe
FROM msstatuspendidikan sp LEFT JOIN
mspencaker p
ON sp.IDStatusPendidikan = p.IDStatusPendidikan AND
p.RegisterDate BETWEEN '2019-01-01' AND '2019-03-01' LEFT JOIN
mspengalaman g
ON g.IDPencaker = c.IDPencaker AND
g.StatusPekerjaan = 0
GROUP BY sp.IDStatusPendidikan;
Notes:
The JOINs have been replaced with LEFT JOINs.
Filtering conditions on all but the first table have been moved to the ON clauses.
This replaces the meaningless table aliases with table abbreviations, so the table is easier to read.
Things that looks like numbers probably are numbers, so I removed the single quotes.
This simplifies the counts, using the fact that MySQL treats booleans as numbers in a numeric context.
CONCAT within GROUP_CONCAT, what is wrong with following mysql code ? Please see SQL Fiddle, full code is there.
Let me explain, I have 5 table
cls - List of Classes
sec - List of Sections
fee - List of Fee
cls_sec - List of section assigned to each class
cls_fee - List of fee assigned to each section
Table cls - lists of Class
id | ttl
===========
1 | One
2 | Two
3 | Three
Table sec - lists of section
id | ttl
===========
1 | A
2 | B
Table cls_sec - lists of each section assigned to Class
id | c_id| s_id
=====================
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
Table fee - lists of fee category
id | ttl
===========
1 | Annual
2 | Monthly
3 | Library
Table cls_fee - lists of each fee and amount assigned to Class
id | c_id| s_id| f_id| fee
=====================================
1 | 1 | 1 | 1 | 2000
2 | 1 | 1 | 2 | 500
3 | 1 | 2 | 1 | 3000
4 | 1 | 2 | 2 | 400
5 | 2 | 1 | 1 | 4500
6 | 2 | 1 | 2 | 450
7 | 3 | 0 | 1 | 5000
8 | 3 | 0 | 2 | 600
9 | 3 | 0 | 3 | 300
Here I am trying to include all relation in one GROUP_CONCAT Result
My current output (Class name and section name is fetched repetitively according to fee )
//Class Name - Section Name (if exist) - fee, Class Name - Section Name (if exist) - fee ..
3.Three.Library->300, 3.Three.Monthly->600, 3.Three.Annual->5000,
2.Two-A.Monthly->450, 2.Two-A.Annual->4500, 1.One-A.Monthly->500,
1.One-A.Annual->2000, 1.One-B.Monthly->400, 1.One-B.Annual->3000
with following code
GROUP_CONCAT(DISTINCT CONCAT('\r\n',cls.id,'.',cls.ttl,
COALESCE(CONCAT('-',sec.ttl),''),COALESCE(CONCAT('.',fee.ttl,'->',cls_fee.fee)))
ORDER BY sec.id) AS cls
But what I want (remove duplication class and section)
//Class Name - Section Name (if exists) - fee, fee
3.Three.Library->300,Monthly->600,Annual->5000,
2.Two-A.Monthly->450,Annual->4500,
1.One-A.Monthly->500,Annual->2000,
1.One-B.Monthly->400,Annual->3000
So I add CONCAT within nested CONCAT
GROUP_CONCAT(DISTINCT CONCAT('\r\n',cls.id,'.',cls.ttl,
COALESCE(CONCAT('-',sec.ttl,COALESCE(CONCAT('.',fee.ttl,'->',cls_fee.fee))), ''))
ORDER BY sec.id) AS cls
and got output, but it doesn't fetch as expected, also missing some fee
3.Three,
2.Two-A.Monthly->450, 2.Two-A.Annual->4500,
1.One-A.Monthly->500, 1.One-A.Annual->2000,
1.One-B.Monthly->400, 1.One-B.Annual->3000
MySQL CODE
SELECT
GROUP_CONCAT(DISTINCT CONCAT('\r\n',cls.id,'.',cls.ttl,
COALESCE(CONCAT('-',sec.ttl),''),COALESCE(CONCAT('.',fee.ttl,'->',cls_fee.fee)))
ORDER BY sec.id) AS cls
FROM
cls
LEFT JOIN
cls_sec ON cls_sec.cls = cls.id
LEFT JOIN
sec ON sec.id = cls_sec.sec
LEFT JOIN
cls_fee ON cls_fee.c_id = cls.id
LEFT JOIN
fee ON fee.id = cls_fee.f_id
WHERE
CASE WHEN cls_fee.s_id != 0 THEN cls_fee.s_id = sec.id ELSE cls.id END
SQL Fiddle
You can try to use a subquery to write GROUP_CONCAT from detail by cls.id, cls.ttl then do GROUP_CONCAT again in the main query.
Query 1:
SELECT GROUP_CONCAT(CONCAT(Id,'.',ttl,'.',flag,cls) ORDER BY Id desc,flag) result
FROM (
SELECT
cls.id,
cls.ttl,
COALESCE(CONCAT('-',sec.ttl),'') flag,
GROUP_CONCAT(DISTINCT CONCAT(
COALESCE(CONCAT('.',fee.ttl,'->',cls_fee.fee)))
ORDER BY sec.id) AS cls
FROM
cls
LEFT JOIN
cls_sec ON cls_sec.cls = cls.id
LEFT JOIN
sec ON sec.id = cls_sec.sec
LEFT JOIN
cls_fee ON cls_fee.c_id = cls.id
LEFT JOIN
fee ON fee.id = cls_fee.f_id
WHERE
CASE WHEN cls_fee.s_id != 0 THEN cls_fee.s_id = sec.id ELSE cls.id END
GROUP BY
cls.id,
cls.ttl,
COALESCE(CONCAT('-',sec.ttl),'')
)t1
Results:
| result |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 3.Three..Library->300,.Monthly->600,.Annual->5000,2.Two.-A.Monthly->450,.Annual->4500,1.One.-A.Monthly->500,.Annual->2000,1.One.-B.Monthly->400,.Annual->3000 |
I have a simple table of timestamps , types and counts like
timestamp |t|c
==============
1415024797|1|1
1415025774|1|1
1415202785|1|1
1415204559|1|1
1415204593|1|2
1415629057|1|1
1415791322|2|1
1415797887|1|1
now i get a result which counts the c column group by t and for a certain date YYYY-MM-DD
I have to add 3600 to the timestamp to respect timezone offset!
SELECT From_unixtime(a.timestamp + 3600, '%Y-%m-%d') AS date,
Count(From_unixtime(a.timestamp + 3600, '%Y-%m-%d')) AS count,
a.t AS type
FROM table AS a
WHERE a.timestamp >= 1415322000 AND a.timestamp < 1415926800
GROUP BY From_unixtime(a.timestamp + 3600, '%Y-%m-%d'),
a.t
ORDER BY a.timestamp DESC
with this query I get something like
date |count | type
==========================
2014-12-03 | 3 | 1
2014-12-03 | 1 | 2
2014-12-04 | 3 | 1
2014-12-05 | 3 | 3
2014-12-07 | 4 | 2
2014-12-07 | 7 | 3
....
But I would like to get
date | t_1 | t_2 | t_3
=============================
2014-12-03 | 3 | 1 | 0
2014-12-04 | 3 | 0 | 0
2014-12-05 | 0 | 0 | 3
2014-12-06 | 0 | 0 | 0
2014-12-07 | 0 | 4 | 7
....
So on each line a date with all counts of a certain type.
There are only 3 types possible (1 => t_1, 2 => t_2, 3 => t_3)
Also dates with 0 values (2014-12-06) should be included
to build the query I'll use PHP (foreach)
SELECT From_unixtime(a.timestamp + 3600, '%Y-%m-%d') AS date,
CASE
WHEN type = 1
THEN count
ELSE
NULL
END AS t_1,
CASE
WHEN type = 2
THEN count ELSE NULL END AS t_2,
CASE
WHEN type = 3
THEN count ELSE NULL END AS t_3
FROM...
(?)
There is a relatively simple way of doing this, but the amount of repetitious/ugly code increases along with the number of values of t:
what you basically do is:
select date,
count(case when type=1 then 1 else null end) as t1_count,
count(case when type=2 then 1 else null end) as t2_count...
et cetera
If you are expecting a lot of different values of t, this becomes quite impractical, and you'd have to look at more complex techniques such as this one: http://www.artfulsoftware.com/infotree/qrytip.php?id=523
edit:
If you want to include dates which have no data at all, then you should consider creating a date table, and then 'left joining' it to your results set. you could use this code (https://gist.github.com/johngrimes/408559) - just ignore the first two statements that create numbers tables.
I'm currently trying to make a mysql query that will count the number of zeros and ones per item, in the following way:
Table:
ID | PollID | Value
------------------------------------
1 | 1 | 1
2 | 1 | 1
3 | 2 | 0
4 | 2 | 1
5 | 1 | 0
And the result I want is:
Poll | one | zero
----------------------------------
1 | 2 | 1
2 | 1 | 1
Thanks for the help!
This is the shortest possible answer in MySQL because it supports boolean arithmetic.
SELECT PollID,
SUM(value = 1) AS `One`,
SUM(value = 0) AS `Zero`
FROM tableName
GROUP BY PollID
SQLFiddle Demo
select z.pollid,z.ones,s.zeros
from (select a.pollid,count(a.value) as ones from test a
where a.value=1
group by a.pollid) z
left join
(select b.pollid,count(b.value) as zeros from test b
where b.value=0 group by b.pollid) s
on z.pollid=s.pollid;
try this
select table.pollid,
Switch(table.value Like 1, 1)AS one,
Switch(table.value Like 0, 1)AS zero
from table
group by pollid
I have a table that looks like this one :
+------+------+------------------+
| item | val | timestamp |
+------+------+------------------+
| 1 | 3.66 | 16-05-2011 09:17 |
| 1 | 2.56 | 16-05-2011 09:47 |
| 2 | 4.23 | 16-05-2011 09:37 |
| 3 | 6.89 | 16-05-2011 11:26 |
| 3 | 1.12 | 16-05-2011 12:11 |
| 3 | 4.56 | 16-05-2011 13:23 |
| 4 | 1.10 | 16-05-2011 14:11 |
| 4 | 9.79 | 16-05-2011 14:23 |
| 5 | 1.58 | 16-05-2011 15:27 |
| 5 | 0.80 | 16-05-2011 15:29 |
| 6 | 3.80 | 16-05-2011 15:29 |
+------+------+------------------+
so, the grand total of all item for the day : 16 May 2011 is : 40.09
Now i want to retrieve which items of this list form an amount of 80% of the grand total.
Let me make an example :
Grand Total : 40.09
80% of the Grand Total : 32.07
starting from the item with more percentage weight on the total amount i want to retrieve the grouped list of the item that form the 80% of the grand total :
+------+------+
| item | val |
+------+------+
| 3 | 12.57|
| 4 | 10.89|
| 1 | 6.22|
+------+------+
As you can see the elements in the result set are the elements grouped by item code and ordered from the element with greater percentage weight on the grand total descending until reaching the 80% threshold.
From the item 2 onward the items are discarded from the result set because they exceed the threshold of 80%, because :
12.57 + 10.89 + 6.22 + 4.23 > 32.07 (80 % of the grand total )
This is not an homework, this is a real context where i am stumbled and i need to achieve the result with a single query ...
The query should run unmodified or with few changes on MySQL, SQL Server, PostgreSQL .
You can do this with a single query:
WITH Total_Sum(overallTotal) as (SELECT SUM(val)
FROM dataTable),
Summed_Items(id, total) as (SELECT id, SUM(val)
FROM dataTable
GROUP BY id),
Ordered_Sums(id, total, ord) as (SELECT id, total,
ROW_NUMBER() OVER(ORDER BY total DESC)
FROM Summed_Items),
Percent_List(id, itemTotal, ord, overallTotal) as (
SELECT id, total, ord, total
FROM Ordered_Sums
WHERE ord = 1
UNION ALL
SELECT b.id, b.total, b.ord, b.total + a.overallTotal
FROM Percent_List as a
JOIN Ordered_Sums as b
ON b.ord = a.ord + 1
JOIN Total_Sum as c
ON (c.overallTotal * .8) > (a.overallTotal + b.total))
SELECT id, itemTotal
FROM Percent_List
Which will yield the following:
id itemTotal
3 12.57
4 10.89
1 6.22
Please note that this will not work in mySQL (no CTEs), and will require a more recent version of postgreSQL to work (otherwise OLAP functions are not supported). SQLServer should be able to run the statement as-is (I think - this was written and tested on DB2). Otherwise, you may attempt to translate this into correlated table joins, etc, but it will not be pretty, if it's even possible (a stored procedure or re-assembly in a higher level language may then be your only option).
I don't know of any way this can be done with a single query; you'll probably have to create a stored procedure. The steps of the proc would be something like this:
Calculate the grand total for that day by using a SUM
Get the individual records for that day ordered by val DESC
Keep a running total as you loop through the individual records; as long as the running total is < 0.8 * grandtotal, add the current record to your list