0

I'm having trouble with this SQL:

$sql = mysql_query("SELECT $menucompare ,
  (COUNT($menucompare ) * 100 / (SELECT COUNT( $menucompare )
  FROM data WHERE $ww = $button ))  AS percentday FROM data WHERE $ww >0  ");
  • $menucompare is table fields names what ever field is selected and contains data bellow
  • $button is the week number selected (lets say week '6')
  • $ww table field name with row who have the number of week '6'

For example, I have data in $menucompare like that:

123456bool
521478bool
122555heel
147788itoo

and I want to select those, who have same word in the last of the data and make percentage.

The output should be like that:

  • bool -- 50% (2 entries)
  • heel -- 25% (1 entry)
  • itoo -- 25% (1 entry)

Any clearness to my SQL will be very appreciated. I didn't find anything like that around.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
echo_Me
  • 37,078
  • 5
  • 58
  • 78
  • What errors are you getting (if any)? What exactly is $menucompare? Is it a string containing comma-separated fields' names? Or is it an array of field names? – Nadir Sampaoli May 12 '12 at 19:31
  • Does the `menucompare` field really have composite data like that? Because your existing SQL doesn't make any attempt to separate the word from each value. – Andrew Leach May 12 '12 at 19:35
  • im not getting any error but wrong percent. and $menucompare is table fields names. ok make it easy and do it just menucompare and lets say its table field name – echo_Me May 12 '12 at 19:45

2 Answers2

3

Well, keeping data in such format probably not the best way, if possible, split the field into 2 separate ones.

First, you need to extract the string part from the end of the field.

  • if the length of the string / numeric parts is fixed, then it's quite easy;
  • if not, you should use regular expressions which, unfortunately, are not there by default with MySQL. There's a solution, check this question: How to do a regular expression replace in MySQL?

I'll assume, that numeric part is fixed:

SELECT s.str, CAST(count(s.str) AS decimal) / t.cnt * 100 AS pct
  FROM (SELECT substr(entry, 7) AS str FROM data) AS s
  JOIN (SELECT count(*) AS cnt FROM data) AS t ON 1=1
 GROUP BY s.str, t.cnt;

If you'll have regexp_replace function, then substr(entry, 7) should be replaced to regexp_replace(entry, '^[0-9]*', '') to achieve the required result.

Variant with substr can be tested here.

Community
  • 1
  • 1
vyegorov
  • 21,787
  • 7
  • 59
  • 73
  • Yes, I assumed that the begging of the entry with numeric part there being fixed. The rest deals with letters. – vyegorov May 12 '12 at 21:14
  • Sub-queries have aliases `s` and `t`. `s.str` is the substring that you'd like to analyze. `t.cnt` is a total count of entries in the table. – vyegorov May 12 '12 at 21:29
  • I don't know the right table name. I've provided you with a sample SQL and also setup a test case on the SQL Fiddle. I hope you can adjust provided solution to your needs. – vyegorov May 12 '12 at 21:47
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/11188/discussion-between-vyegorov-and-gosto) – vyegorov May 12 '12 at 21:56
  • +1 for the observation that the column design is sub-optimal (being polite). I'll forego the -1 for a Cartesian product and non-join notation in the FROM clause, but it was tempting. – Jonathan Leffler May 13 '12 at 02:37
  • `ON 1=1`? its condition this ? – echo_Me May 14 '12 at 17:52
  • It is one of the variants of `CROSS JOIN` – vyegorov May 14 '12 at 17:55
  • waw :) , i get it to work thx :) , so i cant touch this 1=1 ? i let it like that ? i mean its not condition or something to change ?anyway it worked well ur sql thx so much – echo_Me May 14 '12 at 19:05
  • You can change second line of the `FROM` clause to look like `CROSS JOIN (SELECT count(*) AS cnt FROM data) AS t` if you like. Otherwise, condition `1=1` should remain. – vyegorov May 14 '12 at 19:11
  • ok thx so much , u very good in sql :) , i thought it dificult ur sql in first time , but when i concentrated what u mean , i understand it. thx again:) i voted up :) – echo_Me May 14 '12 at 19:17
2

When sorting out problems like this, I would do it in two steps:

  1. Sort out the SQL independently of the presentation language (PHP?).
  2. Sort out the parameterization of the query and the presentation of the results after you know you've got the correct query.

Since this question is tagged 'SQL', I'm only going to address the first question.

The first step is to unclutter the query:

SELECT menucompare,
       (COUNT(menucompare) * 100 / (SELECT COUNT(menucompare) FROM data WHERE ww = 6))
          AS percentday
  FROM data
 WHERE ww > 0;

This removes the $ signs from most of the variable bits, and substitutes 6 for the button value. That makes it a bit easier to understand.

Your desired output seems to need the last four characters of the string held in menucompare for grouping and counting purposes.

The data to be aggregated would be selected by:

SELECT SUBSTR(MenuCompare, -4) AS Last4
  FROM Data
 WHERE ww = 6

The divisor in the percentage is the count of such rows, but the sub-stringing isn't necessary to count them, so we can write:

SELECT COUNT(*) FROM Data WHERE ww = 6

This is exactly what you have anyway.

The divdend in the percentage will be the group count of each substring.

SELECT Last4, COUNT(Last4) * 100.0 / (SELECT COUNT(*) FROM Data WHERE ww = 6)
  FROM (SELECT SUBSTR(MenuCompare, -4) AS Last4
          FROM Data
         WHERE ww = 6
       ) AS Week6
 GROUP BY Last4
 ORDER BY Last4;

When you've demonstrated that this works, you can re-parameterize the query and deal with the presentation of the results.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • how u have used last4 in the last query from the previous query ? or u have combined the queries ? – echo_Me May 12 '12 at 21:03
  • i have used this latest query and i get this error `Every derived table must have its own alias` – echo_Me May 12 '12 at 21:20
  • The 'sub-query in the FROM clause' gives the name `Last4` to its single result column; the sub-query generates a result with the 'table name' or alias of `Week6` and with the sole column `Last4`. The error message you report ('Every derived table must have its own alias') would be accurate if the `AS Week6` part were omitted. That (Week6) is the alias for the derived table. The `AS` is optional, but the name is not. – Jonathan Leffler May 13 '12 at 02:25
  • it works now ur sql but it doesnt give any percent its all .0% so its something with this week6 , i dont know what i will put there ! if `$ww` or `$button` or what! because it will not count only week6 it will count what ever week is selected . week7 or wee8 .. . actually i making `$ww` and its 0%. if i make `$button` its the error `You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '6 GROUP BY Last4 ORDER BY Last4'` – echo_Me May 13 '12 at 12:58
  • Well, since you've not actually shown us your table schema, it is a bit tricky to know what you are dealing with. On the whole, that's probably for the best; I don't think I like the design of the table. (Generally, a table with columns like Week1, Week2, Week3, etc is not a sensible design.) Nevertheless, I can try to answer SQL questions about poorly designed tables too. Have you printed out the SQL you are generating before you send it to the server? If not, do so. – Jonathan Leffler May 13 '12 at 14:05
  • The error message says "`6 GROUP BY ...`" as if the 6 was a token on its own. Do you have a space in `) AS Week6 GROUP BY Last4` between the `Week` and the `6`? That would lead to the complaint you show. (And you can/must/should print the SQL so you know exactly what the DBMS is seeing. Debugging blind is pointlessly painful.) – Jonathan Leffler May 13 '12 at 14:33
  • wanna join this chat room ? we can talk about it there [link](http://chat.stackoverflow.com/rooms/11188/discussion-between-vyegorov-and-gosto) – echo_Me May 13 '12 at 15:06