using aggregate function on a calculated column - sql

Trying to use sum() on a newly created calculated column. The calc column name is not recognized in the sum function. Here's my code
select name, is_open,
CASE WHEN text like '%perfect%' or '%amazing%' or '%happy%' or '%delicious%'or '%fabulous%'or '%fantastic%'or '%kind%' THEN 1
WHEN text like '%hate%'or '%horrible%'or '%bad%'or '%angry%'or '%fantastic%'or '%expensive%'or '%disgusting%' THEN -1
END sentiment_rating,
sum(sentiment_rating) as sum
from review as r left join
business as b
on b.id = r.business_id
where is_open is not Null and sentiment_rating is not Null
group by name
order by name ASC

It makes no sense to select both the unaggregated column and the aggregated column. So, just sum() the expression:
select name, is_open,
sum(CASE WHEN text like '%perfect%' or text like '%amazing%' or text like '%happy%' or text like '%delicious%' or text like '%fabulous%' or text like '%fantastic%' or text like '%kind%' THEN 1
WHEN text like '%hate%' or text like '%horrible%' or text like '%bad%' or text like '%angry%' or text like '%fantastic%'or '%expensive%' or text like '%disgusting%' THEN -1
END) as sum_sentiment_rating
from review as r left join
business as b
on b.id = r.business_id
where is_open is not Null and sentiment_rating is not Null
group by name, is_open
order by name ASC;
I'm not sure if you want one row per name or one row per name/is_open. I assumed the latter and added is_open to the GROUP BY.

All your LIKE conditions are syntactically wrong.
You can't have:
text like '%perfect%' or '%amazing%'....
the correct syntax is:
text like '%perfect%' or text like '%amazing%' ....
Then you must sum directly over the calculated with CASE column and include is_open in the grouping columns:
select name, is_open,
SUM(CASE
WHEN text like '%perfect%' or text like '%amazing%' or text like '%happy%' or text like '%delicious%' or text like '%fabulous%' or text like '%fantastic%' or text like '%kind%' THEN 1
WHEN text like '%hate%' or text like '%horrible%' or text like '%bad%' or text like '%angry%' or text like '%fantastic%' or text like '%expensive%' or text like '%disgusting%' THEN -1
END) as sumrating
from review as r left join
business as b
on b.id = r.business_id
where is_open is not Null and sentiment_rating is not Null
group by name, is_open
order by name ASC

Related

Select rows from table with specific string value endings from list

I have a table with two columns item_name, value where item_names looks like "abracadabra_prefix.tag_name". And I need to select rows with tag_names from a list that doesn't have a prefix.
Should be somthing like:
tag_names = ['f1', 'k500', '23_g']
SELECT * FROM table WHERE item_name IN (LIKE "%{tag_names});
input table:
item_name
value
fasdaf.f1
1
asdfe.f2
2
eywvs.24_g
2
asdfe.l500
2
asdfe.k500
2
eywvs.23_g
2
output table:
item_name
value
fasdaf.f1
1
asdfe.k500
2
eywvs.23_g
2
I have tried concatenating a string in a loop to get a query like this:
SELECT * FROM table WHERE item_name LIKE '%f1' OR item_name LIKE '%k500' OR item_name LIKE '%23_g';
But I can have from 1 to 200 tags, and with a large number of tags, this makes the query too complicated,as I understand it.
You can extract the suffix of item_name using substring with regexp and then use the any operator for comparison in the where clause.
select * from the_table
where substring (item_name from '\.(\w+)$') = any('{f1,k500,23_g}'::text[]);
SQL fiddle demo
If you intend to use the query as a parameterized one then it will be convenient to replace '{f1,k500,23_g}'::text[] with string_to_array('f1,k500,23_g', ','), i.e. pass the list of suffixes as a comma-separated string. Please note that this query will result in a sequential scan.
You can use:
UNNEST to extract tag values from your array,
CROSS JOIN to associate tag value to each row of your table
LIKE to make a comparison between your item_name and your tag
SELECT item_name, value_
FROM tab
CROSS JOIN UNNEST(ARRAY['f1', 'k500', '23_g']) AS tag
WHERE item_name LIKE '%' || tag || '%'
Output:
item_name
value_
fasdaf.f1
1
asdfe.k500
2
eywvs.23_g
2
Check the demo here.

Combine codes so that results can display in one table

I wonder how to combine these two into one so that I can have one table displaying both number of "loves" and "hates" together
select count(id) as number
from review
where text like "%love%"
select count(id) as number
from review
where text like "%hate%"
Use case expressions to do conditional aggregation:
select sum(case when text like '%love%' then 1 else 0 end) as love_number,
sum(case when text like '%hate%' then 1 else 0 end) as hate_number
from review
where text like '%love%' or text like '%hate%'
(The WHERE clause isn't really needed, but will keep read-set size down etc.)
Use union all
select count(id) as number
from review
where text like "%love%"
union all
select count(id) as number
from review
where text like "%hate%"
It is not really clear what you want to achieve but perhaps the following SQL is good for you. It shows the count of the reviews:
select count(id) as number
from review
where text like '%love%' or text like '%hate%';
I believe this will fix the issue
SELECT COUNT(SELECT ID FROM REVIEW WHERE text like %Love%) AS LOVE,
COUNT(SELECT ID FROM REVIEW WHERE text like %Hate%) AS HATE
FROM REVIEW

SQL Query; how to display info only where the number of entries in one row is greater than the number of entries in another?

Super simplified code:
SELECT lots_of_stuff.
, A.more_stuff
, B.stuff
, C.things
FROM
table A,
table B,
table C,
where (B.more_stuff = A.stuff)
and things and stuff
and lots more things
and this query has so much crap believe me
and finally
and count(select c.things from table C where c.things like 'CRED')
> count(select c.things from table C where c.things like 'PUR')
;
So the problem is that that last bit does not work (and I'm certain I am doing it wrong entirely, this was just one guess on how to do it.) I was wondering if someone could give me some suggestions.
What I am trying to do is only return the desired fields for cases in which the number of rows containing 'CRED' in a particular field are greater than the number of rows containing 'PUR' in a particular field. (The same field, if that can simplify things.) I would like them to be returned regardless of if 'CRED' or 'PUR' are part of longer words (credit/purchase) or stand alone. They will always be all caps though.
Edit:
What I'm looking for is just those columns I specified
| More_Stuff | Stuff | Things |
| dshsdh | dfh | tjra |
| ddh | ash | ytra |
| shsdh | fgh | sayh |
| hsdh | gnh | tshn |
but only the rows for the customers that have more credit codes than purchase plans. So if they have 3 different entries in 'c.things' with something like "PHONE-CREDIT" or "OFFSET CRED." and 2 different entries in 'c.things' with something like "12 M PURCH PLAN" or "PROMO PURCHASE 36", I want their info to show up. So, when the number of rows with any credit codes is greater than the number of rows with any purchase plans.
My current non-simplified query is already set to sort through all customers, I just need to specify which ones based on this filter.
This can be achieved using WITH Clause in Oracle. The following code
might be close to what you are looking for -
with ds1 as
(
SELECT
lots_of_stuff
, A.more_stuff
, B.stuff
, C.things,
count(c.things) AS COUNT_CRED
FROM
table A,
table B,
table C,
where
(B.more_stuff = A.stuff)
and things and stuff
and lots more things
and this query has so much crap believe me
and finally
and c.things like 'CRED%'
group by
lots_of_stuff.
, A.more_stuff
, B.stuff
, C.things
),
ds2 as
(
SELECT
lots_of_stuff.
, A.more_stuff
, B.stuff
, C.things,
count(c.things) AS COUNT_PUR
FROM
table A,
table B,
table C,
where
(B.more_stuff = A.stuff)
and things and stuff
and lots more things
and this query has so much crap believe me
and finally
and c.things like 'PUR%'
group by
lots_of_stuff.
, A.more_stuff
, B.stuff
, C.things
)
SELECT DS1.*, ds2.*
from ds1, ds2
where count_cred > COUNT_PUR
;
I think you want something like this
WITH cred_count AS
(
SELECT index_field, SUM(CASE WHEN field='CRED' THEN 1 ELSE 0 END) AS cred_count
FROM some_table
GROUP BY index_field
), pur_count AS
(
SELECT index_field, SUM(CASE WHEN field='PUR' THEN 1 ELSE 0 END) AS pur_count
FROM some_table
GROUP BY index_field
)
SELECT somestuff
FROM some_table
LEFT JOIN cred_count ON some_table.index_field = cred_count.index_field
LEFT JOIN pur_count ON some_table.index_field = pur_count.index_field
WHERE COALESCE(cred_count.cred_count,0) > COALESCE(pur_count.pur_count,0)
Note: You can change the WHEN part to be whatever you want to count (eg WHEN field like '%PUR%' would count rows containing the string PUR
Also, I'm making an assumption of having no entries count as 0 -- your business rule for this case might be different.
To filter CRED and PUR in longer words use wildcards like % in the query.
like '%CRED%' -- if CRED can be anywhere in the string
like 'CRED%' -- if CRED is always at the beginning of the string
Note that if it is always at the beginning of the string, you can use an index on the column to make it run faster.
You cannot use an aggregate like count() in the where clause (unless Oracle supports it??)
You can group the rows and use HAVING but in your case, it is actually easier to move the count() inside the subqueries.
SELECT lots_of_stuff.
, A.more_stuff
, B.stuff
, C.things
FROM
table A,
table B,
table C,
where (B.more_stuff = A.stuff)
and things and stuff
and lots more things
and this query has so much crap believe me
and finally
and (select count(c.things) from table C where c.things like '%CRED%')
> (select count(c.things) from table C where c.things like '%PUR%')
;

Transform Numbers to Text

A field in my cube contains numerical values which I would like transformed and displayed as text.
For example
1 is a sale
2 is a return
etc
Is a named caculation best?
Easiest way to do this would be with a case statement,
SELECT
CASE someValue
WHEN 1 THEN 'sale'
WHEN 2 THEN 'return'
END
FROM MyTable ;

SQL query: create category column based on a varchar column in table containing specific values

I have a table similar to the following:
Date Description Value1 Value2
01/01/2012 shiny colour 2 0
01/01/2012 yellow colour 2 2
03/01/2012 matt colour 2 2
03/01/2012 matt 4 1
03/01/2012 shiny 2 2
I want to write a SELECT SQL query (T-SQL) that will output all of the above columns but also display an extra column as the output of the SELECT statement whose value depends on the presence of the word "colour" in the Description (if "colour" is present it would be one value, if not it would show a different value).
(I would also want to display another extra column on top of that whose value depends on the presence of the words "matt" or "shiny" in the Description column. But I assume the method of doing this would be similar).
I believe I should be able to do this using the COALESCE function but I'm not familiar with this and am struggling to get anything working?
EXTENSION
Hey, thanks for your answers. They're really helpful. I have one more extension to the question. My second generated column relies on info in the first generated column. So something like:
SELECT *,
CASE
WHEN Description LIKE '%colour%' THEN 'SomeValue'
ELSE 'Unclassified'
END AS Category1,
CASE
WHEN AnotherColumn LIKE 'Something' THEN 'SomeValue'
WHEN Category1='Unclassified' THEN 'Unclassified'
ELSE 'Generic'
END AS Category2
FROM table_name
How do I get the output of Category2 to rely on output of Category1? I'm trying something like the above but it's not working.
My extension question was answered here: T-SQL CASE statement relies on another CASE statement in same SELECT query
SELECT *,
CASE WHEN Description LIKE '%colour%' THEN
1
ELSE
0
END AS HasColour,
CASE WHEN Description LIKE '%matt%' THEN
1
ELSE
0
END AS HasMatt,
CASE WHEN Description LIKE '%shiny%' THEN
1
ELSE
0
END AS HasShiny
FROM table_name
You would just add more columns for all the different words that you want to search for. Obviously you can change the return type of the columns to whatever you want, but I thought a boolean would be suitable in this situation.
Unless I misunderstand what you are asking, you could use a case statement:
SELECT Date,
Description,
Value1,
Value2,
Case when Description like '%colour%' then OTHERCOL else OTHERCOL2 end as Colourful,
Case when Description like '%matt%' then OTHERCOL else OTHERCOL2 end as Matt,
Case when Description like '%shiny%' then OTHERCOL else OTHERCOL2 end as Shiny,
FROM yourTable