Creating alternating 0 and 1 values based on changing data value - sql

I have data in my sql database and need to create changeControl value.
data changeControl
M-0101 0
M-0101 0
M-02 1
M-03 0
OT-014 1
OT-014 1
M-228 0
M-228 0
Are there any way to create this changeControl value depend on data?

There is an easy way, but it depend on your DB.
In SQL Server and in Oracle you can use DENSE_RANK() to get the order of the values, using that you'll have the same number for equal values
In SQL Server
SELECT data
, (DENSE_RANK() OVER (ORDER BY data) - 1) % 2 changeControl
FROM Table1
In Oracle the % is not present, we need to use the function MOD()
SELECT data
, MOD((DENSE_RANK() OVER (ORDER BY data) - 1), 2) changeControl
FROM Table1
In MySQL there is no DENSE_RANK, but there is another way to get the result
SELECT data, changeControl
FROM (SELECT #last
, data
, #id := CASE WHEN #last <> data THEN 1 - #id
WHEN #last = data THEN #id
ELSE 0
END changeControl
, #last:= data
FROM Table1
, (SELECT #id := 0) a) b
if you don't mind additional column you can run directly the subquery.
p.s.: If you don't specify what DB you're using we have to guess.

You need to first break your data into groups, and assign each group a number.
Then join this information with main table, sort by data, and take modulo by two from group number - this will be your changeControl column.
select tn.*, t.RN % 2 as changeControl from tableName tn
left join
(select ROW_NUMBER() OVER (ORDER BY data) AS RN, data
from tableName group by data) t
on t.data = tn.data
order by tn.data
This problem cannot be solved by taking modulo by two of id or data hash - id keeps changing even for identical values, and two sequential hashes although may be different, can both be even, producing same 'changeControl' value.

To implement this, you should handle the RowStyle event of the GridView. Here is some sample code:
using DevExpress.XtraGrid.Views.Grid;
private void gridView1_RowStyle(object sender,
DevExpress.XtraGrid.Views.Grid.RowStyleEventArgs e) {
GridView View = sender as GridView;
if(e.RowHandle >= 0) {
int changeControl = Convert.ToInt32(View.GetRowCellValue(e.RowHandle, View.Columns["changeControl"]));
if(changeControl == 1) {
e.Appearance.BackColor = Color.Salmon;
}
else
e.Appearance.BackColor = Color.SeaShell;
}
}
Please also review this example:
How to change a row style based on a column value

You can create alternatining 0 and 1 values for change control column based on where id is odd or even
SELECT id , data ,
CASE WHEN id%2=0 THEN 1 ELSE 0 END as changecontrol
FROM tableName
EDIT
SELECT id , data ,
CASE WHEN
RIGHT(data,LEN(data) - CHARINDEX('-',data)) % 2 = 0
THEN 1
ELSE 0 END as changecontrol
FROM tableName

Related

SQL Select row depending on values in different columns

I've already found so many answers here but now I can't seem to find any to my specific problem.
I can't figure out how to select a value from a row depending on the value in different columns
with the below table, I want to achieve the following results.
in case the value in column stdvpuni = 1 then return values / contents from this row for the article (column art).
in case the value in column stdvpuni = 0 then return values / contents from the row where STDUNIABG = 1 for this article (column art).
You seem to want one row part art, based on the content of other rows. That suggests using row_number():
select t.*
from (select t.*,
row_number() over (partition by art order by stdvpuni desc, STDUNIABG desc) as seqnum
from t
) t
where seqnum = 1;
You don't specify what to do if neither column is 1. You might want a where clause (where 1 in (stdvpuni, STDUNIABG)) or another condition in the order by.
I do not know what values / contents is, but I suppose that's easy for you to figure out. So, I will focus on the way to select this:
SELECT
CASE
WHEN current.stdvpuni = 1 THEN 'values / contents of current row'
ELSE 'values / contents of other row'
END
FROM yourtable current
JOIN yourtable other
ON other.stdvpuni = 1;
Use your conditions with NOT EXISTS in the WHERE clause:
SELECT t1.*
FROM tablename t1
WHERE t1.STDVPUNI = 1
OR (
t1.STDVPUNI = 0 AND t1.STDUNIABG = 1
AND NOT EXISTS (SELECT 1 FROM tablename t2 WHERE t2.ART = t1.ART AND t2.STDVPUNI = 1)
);

Create a new table with columns with case statements and max function

I have some problems in creating a new table from an old one with new columns defined by case statements.
I need to add to a new table three columns, where I compute the maximum based on different conditions. Specifically,
if time is between 1 and 3, I define a variable max_var_1_3 as max((-1)*var),
if time is between 1 and 6, I define a variable max_var_1_6 as max((-1)*var),
if time is between 1 and 12, I define a variable max_var_1_12 as max((-1)*var),
The max function needs to take the maximum value of the variable var in the window between 1 and 3, 1 and 6, 1 and 12 respectively.
I wrote this
create table new as(
select t1.*,
(case when time between 1 and 3 then MAX((-1)*var)
else var
end) as max_var_1_3,
(case when time between 1 and 6 then MAX((-1)*var)
else var
end) as max_var_1_6,
(case when time between 1 and 12 then MAX((-1)*var)
else var
end) as max_var_1_12
from old_table t1
group by time
) with data primary index time
but unfortunately it is not working. The old_table has already some columns, and I would like to import all of them and then compare the old table with the new one. I got an error that says that should be something between ) and ',', but I cannot understand what. I am using Teradata SQL.
Could you please help me?
Many thanks
The problem is that you have GROUP BY time in your query while trying to return all the other values with your SELECT t1.*. To make your query work as-is, you'd need to add each column from t1.* to your GROUP BY clause.
If you want to find the MAX value within the different time ranges AND also return all the rows, then you can use a window function. Something like this:
CREATE TABLE new AS (
SELECT
t1.*,
CASE
WHEN t1.time BETWEEN 1 AND 3 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 3 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_3,
CASE
WHEN t1.time BETWEEN 1 AND 6 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 6 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_6,
CASE
WHEN t1.time BETWEEN 1 AND 12 THEN (
MAX(CASE WHEN t1.time BETWEEN 1 AND 12 THEN (-1 * t1.var) ELSE NULL END) OVER()
)
ELSE t1.var
END AS max_var_1_12,
FROM old_table t1
) WITH DATA PRIMARY INDEX (time)
;
Here's the logic:
check if a row falls in the range
if it does, return the desired MAX value for rows in that range
otherwise, just return that given row's default value (var)
return all rows along with the three new columns
If you have performance issues, you could also move the max_var calculations to a CTE, since they only need to be calculated once. Also to avoid confusion, you may want to explicitly specify the values in your SELECT instead of using t1.*.
I don't have a TD system to test, but try it out and see if that works.
I cannot help with the CREATE TABLE AS, but the query you want is this:
SELECT
t.*,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 3) AS max_var_1_3,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 6) AS max_var_1_6,
(SELECT MAX(-1 * var) FROM old_table WHERE time BETWEEN 1 AND 12) AS max_var_1_12
FROM old_table t;

Only one expression can be specified in the select list w

I am having problem in part of my code anyway to do this
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. The update part is working but how to use insert into to calculate if a condition is not meant it will insert.
IF
/* CHECKLIST TO UPDATE*/
(NOT EXISTS
(SELECT *
FROM ENERGY.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
,ENERGY.D_CHECK_LIST D_CHECK_LIST
WHERE D_ENERGY_REFERENCE.ID = D_CHECK_LIST.ID
AND D_ENERGY_REFERENCE.REFERENCE = 19051
)
)
BEGIN
INSERT INTO DB.D_ENERGY_REFERENCE(ID, REFERENCE_NO, REFERENCE,VALUE_INTEGER)
(SELECT ID,
(SELECT ISNULL(MAX(REFERENCE_NO), 0) + 1 FROM DB.D_ENERGY_REFERENCE),
19051, (SELECT D_CHECK_LIST.ID,
CASE
WHEN CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT) = 0 THEN NULL
ELSE
(
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION IN (2, 3, 50001, 50003, 50004, 50005, 50006, 50020, 50027, 50028) THEN EVALUATION ELSE NULL END) AS FLOAT)
/
CAST(COUNT(CASE WHEN D_CHECK_LIST.EVALUATION NOT IN (0,1) THEN EVALUATION ELSE NULL END) AS FLOAT)
) * 100
END FROM DB.D_CHECK_LIST
GROUP BY D_CHECK_LIST.ID)
FROM DB.D_ENERGY_REFERENCE D_ENERGY_REFERENCE
WHERE D_ENERGY_REFERENCE.ID = ID AND D_ENERGY_REFERENCE.REFERENCE = 19051
GROUP BY D_ENERGY_REFERENCE.ID
)
END
Can you please check this following part in the sub query of your script-
.......
19051,
(
SELECT
D_CHECK_LIST.ID, -- This is the column 1
CASE
WHEN -- Here you are generating column 2 in the sub query
......
)
Here you are selecting 2 column - one is "D_CHECK_LIST.ID" and other one is generation through CASE WHEN statement. I think you should SELECT any 1 column from those 2 column. If both are required, you can use separate Sub query for that.
The ERROR code "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS" is self explanatory that you can not implement a Sub Query with more than 1 column selected unless the Sub Query is using inside EXISTS method.

SQL Group By and assign highest a value

I am struggling with the SQL (mssql) to manipulate my data as i need it. I have a table like this;
SOMEID, SOMEFIELD, DATE
5 True 01-01-2010
5 True 01-01-2011
5 False 05-05-2012
7 True 05-05-2011
7 False 06-07-2015
What I am trying to achieve is to add another column which assigns the value 1 if they are the most recent for that ID, and 0 if not. So in the above data example the new column values from top to bottom would be 0, 0, 1, 0, 1.
I know I need to group by date but am having trouble assigning the values.
Thanks for any pointers!
You can use row_number() in SQL Server like this:
select *
, case when (row_number() over (partition by SOMEID order by [Date] desc)) = 1 then 1 else 0 end seq
from
yourTable
order by
SOMEID, [Date];
SQL Fiddle Demo
You can use a self join to get the highest row per group then in update query use a case statement to assign value to new column
update a
set a.[somecol] = case when b.[SOMEID] is null then 1 else 0 end
from demo a
left join demo b on a.[SOMEID] = b.[SOMEID]
and a.[DATE] < b.[DATE]
DEMO
try this
SELECT SOMEID, SOMEFIELD, DATE
, CASE WHEN (SELECT MAX(SubTab.Date)
FROM myTable SubTab
WHERE SubTab.SOMEID = myTable.SOMEID
) = myTable.DATE
THEN 1 ELSE 0 END
FROM myTable

How to solve Divide by Zero exception in SQL stored procedure?

When I am executing my stored procedure it is throwing Divide By zero Exception. Because In my database there is no data for some months. How can I solve this?
Below is the my query.
#diffNSVY FLOAT = 0 --I have declared #diffNSVY as optional parameter.
SET #diffNSVY = CASE
WHEN (select top 1 NSV from #temp where rn = 1) < 0 THEN 0
ELSE (((select top 1 NSV from #temp where descrn = 1) - (select top 1 NSV from #temp where rn = 1))*1.0)/(select top 1 NSV from #temp where rn = 1)
END
I am inserting a result set into #temp table. NSV is a column name. rn is rownumber.descrn is also row number in decreasing order.
How can I modify my query?
Please reply.
Regards,
NSJ
First, I would rebuild your script so I didn't need to repeat complex expressions (the subselects, to be precise) more than once.
If possible, use SELECT instead of SET, like this:
SELECT #diffNSVY = CASE
WHEN rn.NSV < 0 THEN 0
ELSE (descrn.NSV - rn.NSV) * 1.0 / rn.NSV /* extra '()' are removed as unneeded */
FROM
(select top 1 NSV from #temp where rn = 1) AS rn,
(select top 1 NSV from #temp where descrn = 1) AS descrn
Next, ask yourself, what the result should be in case of division by zero. Should it be zero as well? Then the next optimisation step would be simply this:
SELECT #diffNSVY = CASE
WHEN rn.NSV <= 0 THEN 0 /* changed '<' to '<=' to account for division by zero */
ELSE (descrn.NSV - rn.NSV) * 1.0 / rn.NSV
FROM
(select top 1 NSV from #temp where rn = 1) AS rn,
(select top 1 NSV from #temp where descrn = 1) AS descrn
But if you wish the result to become undefined (NULL) so you process it later, here's how you can achieve this:
SELECT #diffNSVY = CASE
WHEN rn.NSV < 0 THEN 0
ELSE (descrn.NSV - rn.NSV) * 1.0 / CASE rn.NSV WHEN 0 THEN NULL ELSE rn.NSV END
FROM
(select top 1 NSV from #temp where rn = 1) AS rn,
(select top 1 NSV from #temp where descrn = 1) AS descrn
Generally, I find this pattern useful when I need to secure myself from divide-by-zero errors. I often use it like this:
...ISNULL(some_expression / CASE #Value WHEN 0 THEN NULL ELSE #Value END, 0)...
Sometimes I use it without ISNULL in which case I process the possible NULL result later using some more sophisticated logic.
EDIT: Oh, and one more thing: with SELECT you can have several assignments at once, like this:
SELECT
#Var1 = expression1,
#Var2 = expression2,
...
Could this possibly help you to simplify your query too?
That expression of yours is very unclear and hard to understand, and you're selecting the same value several times which is totally unnecessary - so my recommendation would be:
try to first determine all the bits and pieces that might go into your calcuation - put the results of those select top 1 .... queries into variables
then check before you divide by zero, and if you divisor would be zero, you need to think of another solution / another value to use instead...
Your problem is this: you're currently only checking for your one value being < 0 and then your return 0 - otherwise (including when that value is = 0) you return an expression which is a division by exactly that value.... You need to add one more special case: if that value is = 0, you cannot use your expression since that results in the divide by zero exception - you need to return some other value in this case!
So your code would be something like:
DECLARE #diffNSVY FLOAT = 0 --I have declared #diffNSVY as optional parameter.
DECLARE #RNValue INT
SET #RNValue = (SELECT TOP 1 NSV FROM #temp WHERE rn = 1)
DECLARE #DescRNValue INT
SET #DescRNValue = (SELECT TOP 1 NSV FROM #temp WHERE descrn = 1)
SET #diffNSVY =
CASE
WHEN #RNValue < 0 THEN 0
WHEN #RNValue = 0 THEN ....... <-- you need to define a value here! CAnnot divide by #RNValue if it's ZERO !
ELSE ((#DescRNValue - #RNValue) * 1.0) / #RNValue
END
Maybe you need a '<=0' not '<0' in your if clause? You should also probably make sure there's data in your temp table that meets the rn = 1 criteria, otherwise the selection will return null. If all else fails Sql2005 has try catch blocks, so you can catch the divide by zero exception.