Cast decimal as int when a specific value is found - sql

I have a query that compares data between weeks using CTEs. One of things it stores is percentage data. I am trying to convert or cast any value that is equal to 100.00.
For example, here is what the result would look like
Name Percentage Other
App1 99.56 5.5
App2 100.00 6
I am hoping to remove the zero's from the 100. I have tried some case statements but I never get the results I am looking for. Here is what I have now.
SELECT
f.Application,
f.Percentage,
f.Other,
CASE
WHEN f.Percentage = 100.00
THEN 100
END AS Percentage
FROM Table1 f
Currently, the values that are 100.00 are changed to 100. However, everything not equal to 100.00 is nulled out. I can get rid of the NULLs by adding
ELSE f.Percentage
But then 100.00 is not changed.
Any help would be appreciated.

As I mentioned in the comments, you can't have a single SQL column that contains multiple data types.
That being said, whether or not it's useful in your case remains to be seen, but a string-type like nvarchar can handle both, though your code would need to be able to handle them as strings instead of numbers.
An example would be something like this:
SELECT
f.Application,
f.Percentage,
f.Other,
CASE
WHEN f.Percentage = 100.00
THEN '100'
ELSE CAST(f.Percentage as nvarchar(10))
END AS Percentage
FROM Table1 f
The Percentage column would now be of type nvarchar, but it would return values in this fashion:
Name Percentage Other
App1 99.56 5.5
App2 100 6
App3 91.23 3.5
App4 94.41 4.8
App5 100 6

Related

Generate dynamic date columns in a SELECT query SQL

First of I've got a table like this:
vID
bID
date
type
value
1
100
22.01.2021
o
250.00
1
110
25.01.2021
c
100.00
2
120
13.02.2021
o
400.00
3
130
20.02.2021
o
475.00
3
140
11.03.2022
c
75.00
1
150
15.03.2022
o
560.00
To show which values were ordered(o) and charged(c) per Month, I have to like 'generate' columns for each month both ordered and charged in a MSSQL SELECT query.
Here is an example table of what I want to get:
vID
JAN2021O
JAN2021C
FEB2021O
FEB2021C
…
MAR2022O
MAR2022C
1
250.00
100.00
560.00
2
400.00
3
475.00
75.00
I need a posibility to join it in a SQL SELECT in addition to some other columns I already have.
Does anyone has an idea and could help me please?
The SQL language has a very strict requirement to know the number of columns in the results and the type of each column at query compile time, before looking at any data in the tables. This applies even to SELECT * and PIVOT queries, where the columns are still determined at query compile time via the table definition (not data) or SQL statement.
Therefore, what you want to do is only possible in a single query if you want to show a specific, known number of months from a base date. In that case, you can accomplish this by specifying each column in the SQL and using date math with conditional aggregation to figure the value for each of the months from your starting point. The PIVOT keyword can help reduce the code, but you're still specifying every column by hand, and the query will still be far from trivial.
If you do not have a specific, known number of months to evaluate, you must do this over several steps:
Run a query to find out how many months you have.
Use the result from step 1 to dynamically construct a new statement
Run the statement constructed in step 2.
There is no other way.
Even then, this kind of pivot is usually better handled in the client code or reporting tool (at the presentation level) than via SQL itself.
It's not as likely to come up for this specific query, but you should also be aware there are certain security issues that can be raised from this kind of dynamic SQL, because some of the normal mechanisms to protect against injection issues aren't available (you can't parameterize the names of the source columns, which are dependent on data that might be user-generated) as you build the new query in step 2.

SQL Query to return all of the same numbers ignoring if the number is positive or not

I am looking for an SQL query to return all records based on a number. The trick is that the number can be positive or negative, but as long as the number is the same it should return.
So I have a table like this:
1 amt1 100.00
2 amt2 100.00
3 amt3 -100.00
4 amt4 120.00
A query such as this:
Select * from table where amount = '100.00'
Only returns the first 2 rows.
I want to return the first 3 rows, thus ignoring the minus sign but still matching the amount.
Any ideas?
Use in:
where amount in (100.00, -100.00)
Note the single quotes are not necessary.
You can also use abs():
where abs(amount) = 100.00
if you don't care much about indexes or query optimization.
If amount is a number:
select * from table where abs(amount) = 100.00;
If amount is text:
select * from table where amount in ('100.00', '-100.00');

Hive: Create rows with summed data, by date (unknown number of dates)

I am currently working with a Hive Table which contains transactions data and I need to do some basic statistics on these data, and put the results in a new table.
EDIT: I'm using Hive 0.13 on Hadoop 2.4.1.
CONTEXT
First, let me try to present the input table: here's a table with 3 columns, an ID, a date (month/year), and an amount:
<ID> <Date> <Amount>
1 11.2014 5.00
2 11.2014 10.00
3 12.2014 15.00
1 12.2014 7.00
1 12.2014 15.00
2 01.2015 20.00
3 01.2015 30.00
3 01.2015 45.00
... ... ...
And the desired output consist of a table grouped by IDs, where in each line I sum the the amounts, for each corresponding months:
<ID> <11.2014> <12.2014> <01.2015> <...>
1 5.00 22.00 0.00 ...
2 10.00 0.00 20.00 ...
3 15.00 0.00 75.00 ...
... ... ... ... ...
Considering that the original table has >4 million IDs and > 500 million lines, on more then 2 years. It seems pretty hard to hardcode the table by hand since I don't know how many columns I should create.
(I know how many different dates I have, but if the original table grows over 5, 10, 15 years, there is going to be a lot to do by hand and that's risky.)
THE CHALLENGE
I know how to do some basic manipulations and GROUP BYs, I can even do some CASE WHEN, but the tricky part in my problem is that I can not create columns like this (as mentionned above)...
SUM (CASE WHEN Date = 11.2014 THEN Amount ELSE 0 END) AS 11.2014
SUM (CASE WHEN Date = 12.2014 THEN Amount ELSE 0 END) AS 12.2014
SUM (CASE WHEN Date = 01.2015 THEN Amount ELSE 0 END) AS 01.2015
SUM (CASE WHEN Date = ??? THEN Amount ELSE 0 END) AS ???
... because I don't know how many different dates I'll eventually have, so I would need something like this:
SUM (CASE WHEN Date = [loop over each dates] THEN Amount ELSE 0 END)
AS [the date selected in the loop]
THE QUESTION
Do you have something to propose in order to :
How can I loop over all the dates ?
And be able to create a colum for every dates I have without specifying myself the name of the soon to be created column ?
Is it doable in a single HiveQL script ? (not obligated but could be really nice)
I would like to avoid UDF but at this point I'm not sure it's preventable since I haven't find any case that ressemble mine.
Thanks in advance and don't hesitate to ask for more info.
This is too long for a comment.
You cannot do exactly what you want in Hive, because a SQL query has to have a fixed number of columns when it is defined.
What can you do?
The easiest thing is simply to change what you want. Product multiple rows instead of multiple columns:
select id, date, sum(amount)
from table t
group by id, date;
You can then load the data into your favorite spreadsheet and pivot it there.
Other alternatives. You can write a query that will write the appropriate query. This would go through the table, identify the possible dates, and construct a SQL statement. You can then run the SQL statement.
Or, you could use some other data types, such as a list or JSON to store the aggregated values in one row.

WHERE varchar = variable length of 0's

Table_A
ID Number
-- ------
1 0
2 00
3 0123
4 000000
5 01240
6 000
The 'Number' column is data type varchar.
EDIT for clarity.
My question is, can I easily pull back all rows of data which contain a variable length string of 0's?
I have tried:
SELECT *
FROM Table_A
WHERE LEFT(Number,1) = '0' AND RIGHT(Number,1) = '0'
Using the above, it would still return the below, using the example table provided.
ID Number
-- ------
1 0
2 00
4 000000
5 01240
6 000
I was looking for a function which I could pass the LEN(Number) int into, and then it generates a string of a specfic character (in my case a string of 0's). I wasn't able to find anything though.
Oh, and I also tried adding a SUBSTRING to the WHERE clause, but sometimes the Number column has a number which has a 0's in the middle, so it still returned strings with other numbers except only 0.
SUBSTRING(Number,ROUND(LEN(Number)/2,0),1) = '0'
Any help is appreciated.
So, you want a string that doesn't contain anything that isn't a 0? Sounds like it's time for a double-negative:
SELECT *
FROM Table_A
WHERE NOT Number like '%[^0]%'
AND number like '0%' --But we do want it to contain at least one zero
(The final check is so that we don't match the empty string)
Answer:
Where number like '%0%'
Your can use this query :
SELECT * FROM Table_A WHERE Number LIKE '%0%';
It'll solve your problem.
SELECT *
FROM yourtable
WHERE len(Number) - len(replace(number,'0','')) >= 0
One more approach
You can use this following one also,you will get your expected result.
SELECT *
FROM Table_A
WHERE Nunber not like '%[1-9]%'
Thanks.

SQL Query to separate data into two fields

I have data in one column that I want to separate into two columns. The data is separated by a comma if present. This field can have no data, only one set of data or two sets of data saperated by the comma. Currently I pull the data and save as a comma delimited file then use an FoxPro to load the data into a table then process the data as needed then I re-insert the data back into a different SQL table for my use. I would like to drop the FoxPro portion and have the SQL query saperate the data for me. Below is a sample of what the data looks like.
Store Amount Discount
1 5.95
1 5.95 PO^-479^2
1 5.95 PO^-479^2
2 5.95
2 5.95 PO^-479^2
2 5.95 +CA8A09^-240^4,CORDRC^-239^7
3 5.95
3 5.95 +CA8A09^-240^4,CORDRC^-239^7
3 5.95 +CA8A09^-240^4,CORDRC^-239^7
In the data above I want to sum the data in the amount field to get a gross amount. Then pull out the specific discount amount which is located between the carat characters and sum it to get the total discount amount. Then add the two together and get the total net amount. The query I want to write will separate the discount field as needed, see store 2 line 3 for two discounts being applied, then pull out the value between carat characters.
For SQL Server:
You can use ChardIndex(',',fieldname) in a sql statement to find the location of the comma and then Substring to parse out the first and second field.
For Oracle you can use a case statement like this in your select clause. Use one for each of the two discounts:
CASE WHEN LENGTH(foo.discount) > 0 AND INSTR(foo.discount,',') > 0 THEN
SUBSTR(foo.discount,1,INSTR(foo.discount,',',1,1)) ELSE foo.discount END AS discount_column_1
I finally figured out exactly how to separate the fields as I need them. Below is the code that breaks the discount field into two. I can now separate the fields as needed and insert the data separated into a temp table then use a similar set of code to pull out the exact amount enclosed by the carat characters. Thanks for the help in the two answers above. I used a combination of both to get exactly what I needed.
CASE LEN(X.DISCOUNT)-LEN(REPLACE(X.DISCOUNT,',',''))
WHEN 1 THEN SUBSTRING(X.DISCOUNT,1,CHARINDEX(',',X.DISCOUNT)-1)
ELSE X.DISCOUNT
END 'FIRST_DISCOUNT',
CASE LEN(X.DISCOUNT)-LEN(REPLACE(X.DISCOUNT,',',''))
WHEN 1 THEN SUBSTRING(X.DISCOUNT,CHARINDEX(',',X.DISCOUNT)+1,LEN(X.DISCOUNT)-CHARINDEX(',',X.DISCOUNT)+1)
ELSE ''
END 'SECOND_DISCOUNT'
This alternative solution uses LEFT and RIGHT functions for split the column.
select Store, Amount,
Discount1 = CASE
WHEN CHARINDEX(',',Discount) > 1 THEN LEFT(Discount, CHARINDEX(',',Discount)-1 )
ELSE Discount END,
Discount2 = CASE
WHEN CHARINDEX(',',Discount) > 1 THEN RIGHT(Discount, LEN(Discount) - CHARINDEX(',',Discount)-1 )
END
from #Temp