I have a problem on this particular sql query.
I have list of last names in the column emp_last_name in the table emp_last_name (same table and column name)
And I wanted to search for the 2 last names using the emp_last_name table.
This is what I came up with:
select count(a.emp_last_name) Zykh, count(b.emp_last_name) Vickson
from emp_last_name a, emp_last_name b
WHERE a.emp_last_name LIKE 'Zykh%' and b.emp_last_name LIKE 'Vickson%';
but it seems to show an incorrect result with having the same value from both tables.
btw the incorrect value is 28712 for both tables (dunno how it came to that)
I learned the right value by having to make two queries but it is not what was asked.
This is what I wanted it to look like:
Zykh
Vickson
148
194
can someone help?
A typical way to approach this (the where statement is not necessary, but might improve performance if you have a large table):
SELECT
SUM(CASE WHEN a.emp_last_name LIKE 'Zykh%' THEN 1 ELSE 0 END) AS Zykh,
SUM(CASE WHEN a.emp_last_name LIKE 'Vickson%' THEN 1 ELSE 0 END) AS Vickson
FROM emp_last_name a
WHERE a.emp_last_name LIKE 'Zykh%'
OR a.emp_last_name LIKE 'Vickson%';
To explain the result of 28,712 your received before: you created a cross join (Cartesian Product) between the a and b table, resulting in the product of both answers (148*194 = 28,712)
I'm trying to generate a result set from a table with effectively a unique/primary key as billyear, billmonth and type along with cost and consumption. So there could be 3 bill year and bill month identical entries but the type could be one of three values: E, W or NG.
I need to create a result set that has just one row per billyear and billmonth entry.
(
select month as billmonth, year as billyear, cost_estimate as eleccost, consumption_estimate as eleccons from tblbillforecast where buildingid=19 and type='E'
)
UNION (
select month as billmonth, year as billyear, cost_estimate as gascost, consumption_estimate as gascons from tblbillforecast where buildingid=19 and type='NG'
)
UNION (
select month as billmonth, year as billyear, cost_estimate as watercost, consumption_estimate as watercons from tblbillforecast where buildingid=19 and type='W'
)
This generates a result set with only billmonth, billyear, eleccost and eleccons columns. I've tried all kinds of solutions but the above example is the simplest to show where it's going wrong.
Additionally it still has 3 rows per billmonth/billyear unique combination instead of merging to one.
UPDATE:
Sample data
SELECT month AS billmonth,
year AS billyear,
SUM(CASE type WHEN 'E' THEN cost_estimate END) AS eleccost,
SUM(CASE type WHEN 'NG' THEN cost_estimate END) AS gascost,
SUM(CASE type WHEN 'W' THEN cost_estimate END) AS watercost
FROM tblbillforecast
WHERE buildingid=19
GROUP BY billmonth, billyear;
Result:
Expected result, eg:
year | month | eleccost | gascost | watercost
2018 | 1 | 32800 | 4460 | 4750
This is behaving correctly. An SQL query result set has one name per column, and this name applies to all the rows. So if you try to rename the column in the second or subsequent queries of the UNION, those new names are ignored. The name of the column is determined only by the first query of the UNION.
Additionally it still has 3 rows per billmonth/billyear unique combination instead of merging to one.
That's also correct behavior, according to the query you tried. UNION does not merge multiple rows into one, it only appends sets of rows.
As Akina hinted in the comments above, you may use multiple columns:
SELECT month AS billmonth,
year AS billyear,
SUM(CASE type WHEN 'E' THEN cost_estimate END) AS eleccost,
SUM(CASE type WHEN 'NG' THEN cost_estimate END) AS gascost,
SUM(CASE type WHEN 'W' THEN cost_estimate END) AS watercost
FROM tblbillforecast
WHERE buildingid=19
GROUP BY billmonth, billyear;
This uses GROUP BY to "merge" rows together, so you get one row in the result per month/year.
A quick bit of guidance on various data shaping operations in SQL:
JOIN - makes resultsets wider (more columns) by bringing together tables/resultsets in a side-by-side fashion generating output rows that have all the columns of the two input column sets
SELECT - typically makes resultsets narrower by allowing you to specify which columns you're interested in and which you are not; by not mentioning an available column it disappears meaning you output fewer columns
UNION - makes resultsets taller (more rows) by bringing together resultsets and outputting one on top of the other. Because columns always have a fixed data type and one name, you must have the same number of and type of, and order of columns
WHERE - makes resultsets shorter (fewer rows) by allowing you to specify truth based filters that exclude rows
It's not hard and fast; you can use select to create more columns too, but just in a very rudimentary sense these concepts hold true - JOIN to widen, UNION for taller, SELECT for narrower and WHERE for shorter. All the work you do with SQL is a data shaping exercise; you're either paring a rectangular block of data down or extending it, and in either a vertical or horizontal direction (or a mix).
I'm not going to get into grouping because that mixes rows up, and isn't something you tried in the question.. The reason for me writing this out was purely because you'd attempted to use a UNION (height-increasing) operation when you actually wanted a widen which, regardless of how it is done (JOIN or as per Bill's answer a SELECT+GROUP, which is valid, but relies on the "mixes rows up" aspect of grouping), specifically isn't done with a UNION. Union only makes stuff taller.
To give an example of how it might be done in an alternative way to Bill's approach, this task of yours has one huge table that is "too tall" - it uses 3 rows where 1 would do, if only it were a bit wider. That is to say if only there were 3 columns for electric/gas/water then we wouldn't need 3 rows with 1 utility in each.
Of course, we have this "one utility per row" because it is very flexible. Database tables don't have varying numbers of columns but they DO have varying numbers of rows. If a new bill type came along tomorrow - internet - no table changes are needed to accommodate it; add a new type I, and away you go, adding another row. We now store 4 rows of 1 utility where 1 row with 4 columns would do, but crucially we didn't have to change the table structure. We could have infinite different kinds of bills, and not need infinite columns because we can already have infinite rows
So you want to reshape your data from 4-rows-by-1-column to 1-row-by-4-columns. It could be solved as :
narrow the table to just year,month,building,type,cost AND shorten it to just electricity
separately narrow the table to just year,month,building,type,cost AND shorten it to just gas
separately narrow the table to just year,month,building,type,cost AND shorten it to just water
join (widening) all these newly created result sets , then narrow to remove the repeated year,month,building,type columns
That would look like:
SELECT e.year, e.month, e.building, e.cost, g.cost, w.cost
FROM
(SELECT year,month,building,cost FROM t WHERE type = 'E') e
JOIN
(SELECT year,month,building,cost FROM t WHERE type = 'NG') g
ON
e.year = g.year AND e.month = g.month AND e.building = g.building
JOIN
(SELECT year,month,building,cost FROM t WHERE type = 'W') w
ON
e.year = w.year AND e.month = w.month AND e.building = w.building
WHERE
e.building = 19
You can see clearly the 3 narrowing-and-shortening operations that pick out "just the gas", "just the electric", and "just the water" - they're the (SELECT year,month,building,cost FROM t WHERE type = 'NG') and that's what reduces the height of the original table, making it three times shorter than it was in each case. If we had 999 rows X 5 cols in the big table it goes to 3 sets of 333 x 5 rows each
You can see that we then JOIN these together to widen the results - our e.g 3 sets of 333 x 5 rows each widens to 333 x 15 when JOINed..
Then went from 333x15 down to 333 X 7 when SELECTed to ditch the repeated columns
It's likely not perfect (I'd perhaps left join all 3 onto a 4th set of numbers that are just the common columns in case some utilities aren't present for a particular month), and perhaps some people will come along complaining that it's less performant because it hits the table 3 times.. All that is accessory to the point I'm making about SQL being an exercise in reshaping data - tables are the starting blocks of data and you cut them up narrower and shorter, then stick them together side by side, or on top of each other and that becomes your new data block that's maybe wider, higher, both.. In any case it's definitely a different shape to what you started with. And then you can cut and shape again, and again..
Go with Bill's conditional agg (though this way would be fine if there is one row per building/year/month) but take away a stronger notion about in what direction these common operations (SELECT/JOIN/WHERE/UNION) reshape your data
Footnote about Bill's conditional aggregation (I know I said I wouldn't talk about it but it might make more sense to now). If you have:
Type, Cost
E, 123
NG, 456
W, 789
And you do a
SELECT
CASE WHEN Type = 'E' THEN Cost END as CostE,
CASE WHEN Type = 'NG' THEN Cost END as CostG,
CASE WHEN Type = 'W' THEN Cost END as CostW
...
It spreads the data out over more columns - the data has "gone from vertical to diagonal"
CostE, CostNG, CostW
123, NULL, NULL
NULL, 456, NULL
NULL, NULL, 789
But it's still too tall. If you then run a GROUP BY, which mixes rows up and ask for e.g. just the MAX from each column, then all the NULLs will disappear (because there is a non null somewhere in the column, and NULL is lost if there is a non null, no matter what you're doing) and the rows collapse, mixing together, into one:
CostE, CostNG, CostW
123, 456, 789
The data has pivoted round from being vertical, to being horizontal - another data shaping. It was pulled wider, and squashed flatter
complete newbie in SQL here. I have an assignment where I was supposed to create a whole bunch of tables and then perform certain filtering among them.
As seen from the picture, these are actually 2 distinct titles (from a larger table that has more of these) but each of them comes as a book, audio and video copy, hence why there are 3 rows for each distinct title.
Is there any way that I can scan through the multiple rows based on the Title and then return just a single row for each Title stating whether it's available as video and audio? So as long as in any 3 rows, the answer is yes in the "available_in_audio" or "available_in_video", that 'yes' will override the 'no' for any columns scanned before or after it.
For example for the 3 Harry Potter and the Chamber of Secrets rows, I just want a single row where "Available_in_Audio" is Yes and "Available_in_Video" is Yes.
If both available_as_video and available_as_audio are "No", means it's a book, if available_as_audio is "Yes" means it's an audio copy and available_as_video means it's a video copy
Thank you so much and sorry for the long question!
Try this
SELECT Title,
CASE WHEN (MAX(CASE WHEN Available_in_Audio = 'Yes' THEN 1 ELSE 0 END)) = 1 THEN 'Yes' ELSE 'No' END) AS Available_in_Audio,
CASE WHEN (MAX(CASE WHEN Available_in_Video = 'Yes' THEN 1 ELSE 0 END)) = 1 THEN 'Yes' ELSE 'No' END) AS Available_in_Video,
FROM <YourTable>
GROUP BY TITLE
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.
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