SQL/C# Windows App - Several Counts From One DataSet? - sql-server-2008

I have a C# Windows app with an SQL table holding voter information. One of the stored fields is 'Party' with stored values of 'Dem', 'Rep', 'Ind', 'Other'. I want to total by these values and use the count function to show total of all records. I know how to use count to get the total of all the records in the the record set but how do you count each value in the field.
I have a form with textboxes for Total Records, Total Dem, Total Rep, Total Ind and Total Other. There is a list box with radio buttons. The default button is 'All' showing all records. There is a radio button for each of the values (Dem, Rep, Ind and Other). When the radio buttons are selected the list is narrowed by the selection. The total in the textboxes does not change and always shows the total for each value.
Thanks in advance.

SELECT COUNT(1) AS total,
COUNT(CASE WHEN Party = 'Dem' THEN 1 ELSE 0 END) AS demTotal,
COUNT(CASE WHEN Party = 'Rep' THEN 1 ELSE 0 END) AS repTotal,
COUNT(CASE WHEN Party = 'Ind' THEN 1 ELSE 0 END) AS indTotal,
COUNT(CASE WHEN Party = 'Other' THEN 1 ELSE 0 END) AS otherTotal
FROM MyTable
Something like following would work and place the data in columns. Depending on the size of the data, however, this may not be the most efficient. Probably a simple group by would work the best (just tally up the results after you get them).
SELECT Party, COUNT(1) AS total
FROM MyTable
GROUP BY Party
Update: Make sure that Party is indexed!

A straightforward way would be to build a scalar function for each count. Something like
select #return = count(party) where party = 'Dem'
And then a view that holds the counts for each party. There are more performant ways to do this but from your question it sounds like your just getting up off the ground and this would probably be the most straightforward way for you.
Learn about scalar functions here:
http://msdn.microsoft.com/en-us/library/ms186755.aspx
And views here:
http://msdn.microsoft.com/en-us/library/ms187956.aspx
A better way (for the database) would be to build a view that uses "group by" but it would return rows instead of columns which will create a little more work for you when setting the values to each of your c# controls.
http://msdn.microsoft.com/en-us/library/ms177673.aspx

Related

how to get total and total of subset using mysql?

I am trying to have a mysql query return a calculated result, but am having some challenges as I am only able to get it to return 1 value.
http://sqlfiddle.com/#!9/5e9276/1
Is it possible to get total count for agents that are robot types within a department, and then the total of agents within department to calculate %?
example:
department 1, has 4 out of 5 robots. (80% robots)
the type field may not always have the same value, but will contain at least the keyword 'robot' or 'human'.
I know I can get the % programmatically, but wanted to check if there was a way to do this directly using mysql query.
Any help is appreciated.
Thanks,
Maybe this is what you want:
SELECT
department,
SUM(type LIKE '%robot%') robots,
COUNT(department) total,
SUM(type LIKE '%robot%') / COUNT(department) robot_percentage
FROM agents
GROUP BY department;
Example SQL Fiddle
To format the robot_percentage with percent sign you coud do:
CONCAT(FORMAT( (SUM(type LIKE '%robot%')*100 / COUNT(department)),2),'%') robot_percentage

Looping in Union All

I'm writing a stored procedure that will display yes/no counts by an alcohol category and job number. I started programming the current categories - wine, beer, whisky - via an union all but thinking ahead there might be more categories and I visualize this code getting hefty in size. Is it possible to perform a union all in a loop and then pass the alcohol category argument? Trolled the internet and have seen very little on the subject so any help or guidance will be most appreciated.
The start of my code...
delimiter $$
create procedure alc_cat_yn (in jid int)
begin
select
cast(concat(jobid,' - Wine')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when wine_id=1 then 1 else 0 end) as y
,sum(case when wine_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid
union all
select
cast(concat(jobid,' - Beer')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when beer_id=1 then 1 else 0 end) as y
,sum(case when beer_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid
union all
select
cast(concat(jobid,' - Whisky')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when whisky_id=1 then 1 else 0 end) as y
,sum(case when whisky_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid;
end
In theory, you could have a loop which builds the query string in a loop and executes it as a prepared statement. Doing so, however, is bad practise. Instead, you should avoid having different columns for your different alcohol categories. Use a single column with multiple rows. Each row would contain the jobid, the alcohol category and a value (e.g. 1 or 2).
I'm a bit mystified why your columns are called *_id, as you seem to store some yes/no information, and not an identifier for some row in another table. You might want to choose a less misleading name.
For the category, you could either use an enum, or the name stored in a string, or a number referencing the primary key of some other table that lists your kinds. The enum will mean that every new category requires a change to the database schema. A string might consume considerable amounts of memory, particularly if you choose long names. Therefore, references to another table are the most flexible solution and probably your best choice in the long run.
You could still provide the current structure as a view, based on the extended table. If you use a new name for the restructured table, and reuse the current name for this view, then backwards compatibility with existing code could be maintained.
Little note: MySQL uses 0 or 1 to represent boolean values. So instead of writing case when foo=bar then 1 else 0 end you could simply write foo=bar. This will make your code much shorter. Otoh, it will also make it harder to read at first glance, so perhaps best place a comment somewhere about this use.

Formatting a MySQL Query result

I've currently got a table as follows,
Column Type
time datetime
ticket int(20)
agentid int(20)
ExitStatus varchar(50)
Queue varchar(50)
I want to write a query which will break this down by week, providing a column with a count for each ExitStatus. So far I have this,
SELECT ExitStatus,COUNT(ExitStatus) AS ExitStatusCount, DAY(time) AS TimePeriod
FROM `table`
GROUP BY TimePeriod, ExitStatus
Output:
ExitStatus ExitStatusCount TimePeriod
NoAgentID 1 4
Success 3 4
NoAgentID 1 5
Success 5 5
I want to change this so it returns results in this format:
week | COUNT(NoAgentID) | COUNT(Success) |
Ideally, I'd like the columns to be dynamic as other ExitStatus values may be possible.
This information will be formatted and presented to end user in a table on a page. Can this be done in SQL or should I reformat it in PHP?
There is no "general" solution to your problem (called cross tabulation) that can be achieved with a single query. There are four possible solutions:
Hardcode all possible ExitStatus'es in your query and keep it updated as you see the need for more and more of them. For example:
SELECT
Day(Time) AS TimePeriod,
SUM(IF(ExitStatus = 'NoAgentID', 1, 0)) AS NoAgentID,
SUM(IF(ExitStatus = 'Success', 1, 0)) AS Success
-- #TODO: Add others here when/if needed
FROM table
WHERE ...
GROUP BY TimePeriod
Do a first query to get all possible ExitStatus'es and then create your final query from your high-level programming language based on those results.
Use a special module for cross tabulation on your high-level programming language. For Perl, you have the SQLCrossTab module but I couldn't find one for PHP
Add another layer to your application by using OLAP (multi-dimensional views of your data) like Pentaho and then querying that layer instead of your original data
You can read a lot more about these solutions and an overall discussion of the subject
This is one way; you can use SUM() to count the number of items a particular condition is true. At the end you just group by the time as per normal.
SELECT DAY(time) AS TimePeriod,
SUM('NoAgentID' = exitStatus) AS NoAgentID,
SUM('Success' = exitStatus) AS Success, ...
FROM `table`
GROUP BY TimePeriod
Output:
4 1 3
5 1 5
The columns here are not dynamic though, which means you have to add conditions as you go along.
SELECT week(time) AS week,
SUM(ExitStatus = 'NoAgentID') AS 'COUNT(NoAgentID)',
SUM(ExitStatus = 'Success') AS 'COUNT(Success)'
FROM `table`
GROUP BY week
I'm making some guesses about how ExitStatus column works. Also, there are many ways of interpretting "week", such as week of year, of month, or quarter, ... You will need to put the appropriate function there.

Complex MySQL COUNT query

Evening folks,
I have a complex MySQL COUNT query I am trying to perform and am looking for the best way to do it.
In our system, we have References. Each Reference can have many (or no) Income Sources, each of which can be validated or not (status). We have a Reference table and an Income table - each row in the Income table points back to Reference with reference_id
On our 'Awaiting' page (the screen that shows each Income that is yet to be validated), we show it grouped by Reference. So you may, for example, see Mr John Smith has 3 Income Sources.
We want it to show something like "2 of 3 Validated" beside each row
My problem is writing the query that figures this out!
What I have been trying to do is this, using a combination of PHP and MySQL to bridge the gap where SQL (or my knowledge) falls short:
First, select a COUNT of the number of incomes associated with each reference:
SELECT `reference_id`, COUNT(status) AS status_count
FROM (`income`)
WHERE `income`.`status` = 0
GROUP BY `reference_id`
Next, having used PHP to generate a WHERE IN clause, proceed to COUNT the number of confirmed references from these:
SELECT `reference_id`, COUNT(status) AS status_count
FROM (`income`)
WHERE `reference_id` IN ('8469', '78969', '126613', ..... etc
AND status = 1
GROUP BY `reference_id`
However this doesn't work. It returns 0 rows.
Any way to achieve what I'm after?
Thanks!
In MySQL, you can SUM() on a boolean expression to get a count of the rows where that expression is true. You can do this because MySQL treats true as the integer 1 and false as the integer 0.
SELECT `reference_id`,
SUM(`status` = 1) AS `validated_count`,
COUNT(*) AS `total_count`
FROM `income`
GROUP BY `reference_id`

Mysql: Adding product restricted shipping options to cart

I have a custom shop, and I need to redo the shipping. However, that is sometimes later, and in the meantime, I need to add a shipping option for when a cart only contains a certain range of products.
SO there is a ship_method table
id menuname name zone maxweight
1 UK Standard ukfirst 1 2000
2 UK Economy uksecond 1 750
3 Worldwide Air world_air 4 2000
To this I have added another column prod_restrict which is 0 for the existing ones, and 1 for the restricted ones, and a new table called ship_prod_restrict which contains two columns, ship_method_id and item_id, listing what products are allowed in a shipping category.
So all I need to do is look in my transactions, and for each cart, just check which shipping methods are either prod_restrict of 0 or have 1 and have no products in the cart that aren't in the restriction table.
Unfortunately it seems that because you can't values from an outer query to an inner one, I can't find a neat way of doing it. (edited to show the full query due to comments below)
select ship_method.* from ship_method, ship_prod_restrict where
ship_method.`zone` = 1 and prod_restrict='0' or
(
prod_restrict='1'
and ship_method.id = ship_prod_restrict.ship_method_id
and (
select count(*) from (
select transactions.item from transactions
LEFT JOIN ship_prod_restrict
on ship_prod_restrict.item_id = transactions.item
and ship_prod_restrict.ship_method_id=XXXXX
where transactions.session='shoppingcartsessionid'
and item_id is null
) as non_permitted_items < 1 )
group by ship_method.id
gives you a list of whether the section matches or not, and works as an inner query but I can't get that ship_method_id in there (at XXXXX).
Is there a simple way of doing this, or am I going about it the wrong way? I can't currently change the primary shipping table, as this is already in place for now, but the other bits can change. I could also do it within PHP but you know, that seems like cheating!
Not sure how the count is important, but this might be a bit lighter - hard to tell without a full table schema dump:
SELECT COUNT(t.item) FROM transactions t
INNER JOIN ship_prod_restrict r
ON r.item_id = t.item
WHERE t.session = 'foo'
AND r.ship_method_id IN (**restricted, id's, here**)