How to split count() query into 10 groups in my sql - mysql

I am currently using mysql and I have to split the data into 10 groups.
For example, if the total count of data is 90, it should go like
1~9,
10~18,
19~27,
28~36,
37~45,
46~54,
55~63,
64~72,
73~81,
82~90.
if the total count of data is 100, it should go like
1~10,
11~20,
21~30,
31~40,
41~50,
51~60,
61~70,
71~80,
81~90,
91~100.
Can anyone give me a clue to split the data into 10 groups. I used rownum, but it did not work....
select total.row_num,
total.name,
total.reg,
total.id,
total.motspd
from(
select
(#row_num:=#row_num+1) AS row_num,
cg.group_name as name,
td.reg_date as reg,
td.car_id as id,
td.mcu_motspd as motspd
from
cartracker.tracker_data td
left join car c on (c.car_device_no = td.car_id)
left join car_group cg on (c.car_group_no = cg.car_group_no)
where cg.car_group_no = "1"
group by DATE_FORMAT(td.reg_date, "%Y%M%d%h%m")
)total
This is a result of a query, but it shows wrong row numbers.I want row_num goes from 0 to the end number of the data. but, in the picture, it starts from 44,713. can anyone help me to fix row num as it starts from 0 to the end number of the data.
attached image

I am going by the question in the title:
I am currently using mysql and I have to split the data into 10 groups.
That is exactly what the function ntile() does. So:
select t.*,
ntile(10) over (order by <whatever>) as tile
from t;
I have no idea what the query has to do with this question.

Haven't realize OP want with dynamic table BEFORE re-edit, this is not cleaver and require a lot of time to process though. switch a with OP table name and create rownumber first.
DECLARE #TotalNum INT;
DECLARE #Num INT;
DECLARE #NUm2 INT;
DECLARE #COUNTS INT;
SET #COUNTS = (select count(rownum) from a)/10
SET #TotalNum = 10
SET #Num =1
SET #Num2 =0
WHILE #Num <= #TotalNum
BEGIN
update a
set a.flag = #Num
where a.rownum >= (#COUNTS)*#NUM2+1 and a.rownum <= #NUM*(#COUNTS)
SET #Num = #NUM + 1
SET #Num2 = #NUM2 + 1
END

Related

SQL Cursor to determine median value

I am trying to write a Stored Procedure to retrieve the median salary from a table and am having trouble figuring out how to retrieve the data from the cursor.
Currently my code is:
DELIMITER //
CREATE PROCEDURE MedianSalary(OUT median INT)
BEGIN
DECLARE counter int(5) DEFAULT 0;
DECLARE set_size int(5) DEFAULT (SELECT count(*) from employee);
DECLARE median_index int(5) DEFAULT (SELECT floor(count/2));
DECLARE all_salaries CURSOR
FOR SELECT salary from employee,
OPEN all_salaries;
WHILE #counter != #median_index
BEGIN
SET #counter = #counter + 1,
FETCH NEXT from all_salaries,
END;
FETCH all_salaries INTO median;
CLOSE all_salaries;
END //
DELIMITER ;
I can't seem to find any documentation similar to what I am trying to achieve, any help would be greatly appreciated.
I don't have an answer to your stored procedure problem, but note that we can actually find the median from a table in MySQL fairly easily using session variables to simulate the row number:
SET #row_number = 0;
SET #row_count = (SELECT COUNT(*) FROM yourtable);
SELECT AVG(salary) AS median
FROM
(
SELECT (#row_number:=#row_number + 1) AS rn, salary
FROM yourTable
ORDER BY salary
) t
WHERE
(#row_count % 2 = 0 AND rn IN (#row_count / 2, (#row_count / 2) + 1) OR
#row_count % 2 <> 0 AND rn = #row_count / 2);
Demo
Note the ugliness in the WHERE clause has to do with the edge case of your table having an even number of records. In this case, there technically is not a single median record, so instead I report the mean of the two records which sit about the median on either side.

Stop a package if a percentage difference of counts is less than 1%

I have a package that runs weekly but it needs to stop if there is a difference of more than 1% in the counts.
Here is my query to get the percentage of the 2 counts:
USE MandatedReporting
DECLARE #a AS float
DECLARE #b AS float
declare #c as float
SET #a = ( SELECT Row_Count
FROM [MandatedReporting].[dbo].[DCFS_Weekly_File_Row_Count] WITH(NOLOCK)
WHERE TableName = 'MandatedReporting.dbo.MATCH_WEEKLY_V3'
AND RunDate = ( SELECT MAX(RunDate) AS RunDate
FROM [MandatedReporting].[dbo].[DCFS_Weekly_File_Row_Count] AS ThisWeeksData WITH(NOLOCK)
WHERE TableName = 'MandatedReporting.dbo.MATCH_WEEKLY_V3'))
SET #b = ( SELECT Row_Count
FROM [MandatedReporting].[dbo].[DCFS_Weekly_File_Row_Count] WITH(NOLOCK)
WHERE TableName = 'MandatedReporting.dbo.MATCH_WEEKLY_V3'
AND RunDate = ( SELECT MIN(RunDate) AS RunDate
FROM [MandatedReporting].[dbo].[DCFS_Weekly_File_Row_Count] AS ThisWeeksData WITH(NOLOCK)
WHERE TableName = 'MandatedReporting.dbo.MATCH_WEEKLY_V3'
AND ABS(DATEDIFF(DD,GETDATE(),CAST(RunDate AS DATETIME))) < 10))
set #c = (#a-#b) *100.0/#b SELECT #c as 'Count'
SQL Server 2008
Thanks
You are looking for conditional split. After you execute your stored procedure in Execute SQL Task you need to store output in a variable and then implement conditional split based on output.
Only instead of writing out to a file you simply end your Data Flow or else if you want a nuclear option you can throw an error or do the same in stored proc:
begin
raiserror('Foo Bar',16,1)
end

SQL Server T-SQL breaking a string into a temp table for a join

We have a SQL Server Scalar Function and part of the process is to take one of the input values and do the following
'inputvalue'
Create a table variable and populate with the following rows
inputvalue
inputvalu
inputval
inputva
inputv
input
inpu
inp
Then this table is joined to a query, ordered by len of the inputvalue desc and returns the top 1. The actual code is here
DECLARE #Result NVARCHAR(20);
DECLARE #tempDialCodes TABLE (tempDialCode NVARCHAR(20));
DECLARE #counter INT = LEN(#PhoneNumber);
WHILE #counter > 2
BEGIN
INSERT INTO #tempDialCodes(tempDialCode) VALUES(#PhoneNumber);
SET #PhoneNumber = SUBSTRING(#PhoneNumber, 1, #counter - 1);
SET #counter = #counter - 1;
END
SET #Result = (SELECT TOP 1 [DialCodeID]
FROM DialCodes dc JOIN #tempDialCodes s
ON dc.DialCode = s.tempDialCode
ORDER BY LEN(DialCode) DESC);
RETURN #Result
It works fine but I am asking if there is a way to replace the while loop and somehow joining to the inputvalue to get the same result. When I say it works fine, it's too dam slow but it does work.
I'm stumped on how to break up this string without using a loop and to a table variable but my warning light tells me this is not efficient for running against a table with a million rows.
Are you familiar with tally tables? The speed difference can be incredible. I try to replace every loop with a tally table if possible. The only time I haven't been able to so far is when calling a proc from within a cursor. If using this solution I would recommend a permanent dbo.Tally table with a sufficiently large size rather than recreating every time in the function. You will find other uses for it!
declare #PhoneNumber nvarchar(20) = 'inputvalue';
declare #tempDialCodes table (tempDialCode nvarchar(20));
--create and populate tally table if you don't already a permanent one
--arbitrary 1000 rows for demo...you should figure out if that is enough
--this a 1-based tally table - you will need to tweak if you make it 0-based
declare #Tally table (N int primary key);
insert #Tally
select top (1000) row_number() over (order by o1.object_id) from sys.columns o1, sys.columns o2 order by 1;
--select * from #Tally order by N;
insert #tempDialCodes
select substring(#PhoneNumber, 1, t.N)
from #Tally t
where t.N between 3 and len(#PhoneNumber)
order by t.N desc;
select *
from #tempDialCodes
order by len(tempDialCode) desc;

SQLserver Store Column as variable and loop through it

I am still pretty new to SQL server and I am not sure how to do this. I am first creating a table with just the IDs I need:
SELECT DISTINCT
ID_NUMBER
INTO
#IDlist
FROM
V_Rpt_IDs WITH (NOLOCK)
WHERE
ID_NUMBER in (
'1000764169'
,'1005870537'
,'1008053856'
,'1008054376'
,'1008410224'
,'1008411317'
,'1008465318'
,'1008466074'
,'1008492967'
,'1010546872'
,'1010554301')
Select * from #IDlist
And this works fine. But now I would like to declare a variable to represent this column, or each item in this column, so that I can then do a loop where it loops through each ID Number and returns information about each one and then presents all of that as a table. Here is my shot at that:
Declare #IDNumber as VARCHAR(10)
Set #IDNumber = #IDlist.ID_NUMBER
DECLARE #cnt INT = 0
WHILE #cnt < (Select Count(*) From #IDlist)
BEGIN
SELECT TOP 1
NAME
,MAILING_ADDRESS_1
,MAILING_ADDRESS_CITY
,MAILING_STATE
,MAILING_ZIP
from
V_Rpt_Info
WHERE
ID_NUMBER = #IDNumber
SET #cnt = #cnt + 1
END
DROP TABLE #IDlist
But when I Set the #IDNumber variable to #IDlist.ID_NUMBER, it says The multi-part identifier "#IDlist.ID_NUMBER" could not be bound.
How do I do this?
Thanks
The way you set the variable is not correct, SQL doesn't know which ID_NUMBER row it should assign to the #IDNumber variable.
You should do this with a SELECT, for example
SET #IDNumber = SELECT TOP 1 ID_NUMBER FROM #IDlist
But, why would you like to loop through this temporary table this way ? Isn't it possible to join the necessary data with this table instead of doing it one by one ?
Rather then loop through, you're going to want to join your ID table to your V_Rpt_Info view.
SELECT
NAME
, MAILING_ADDRESS_1
, MAILING_ADDRESS_CITY
, MAILING_STATE
, MAILING_ZIP
FROM V_Rpt_Info V
INNER JOIN #IDlist ID
ON V.ID_NUMBER = ID.ID_NUMBER

Arithmetic operation in MySQL through Procedure

I have a table t1 which have a column Marks in this column values are 10, 20, 30, 40.
Now I want to use a procedure to get this result:
Marks Total_Marks
10 10
20 30
30 60
40 100
DELIMITER //
CREATE PROCEDURE Total_Marks ( In Num Int(4) )
Begin
Declare Mark Int(4);
Declare Add_M Int(4);
DECLARE NO_MORE_ROWS BOOLEAN;
DECLARE DataCursor CURSOR FOR SELECT Marks
FROM t1 where marks = Num;
DECLARE DataCursor1 CURSOR FOR SELECT Sum(Marks) FROM t1;
OPEN DataCursor;
FETCH DataCursor INTO Mark;
CLOSE DataCursor;
OPEN DataCursor1;
READ_LOOP1: LOOP
FETCH DataCursor1 INTO Add_M;
IF NO_MORE_ROWS THEN
LEAVE READ_LOOP1;
END IF;
BEGIN
SET Add_M = SUM(Mark);
END;
END LOOP READ_LOOP1;
CLOSE dataCursor1;
SET NO_MORE_ROWS = FALSE;
end //
DELIMITER ;
You don't need a procedure at all, let alone cursors. But what you need, is a column that defines the order of the rows as mentioned in the comments.
create table foo (id int auto_increment primary key, bar int);
insert into foo(bar) values (10), (20), (30), (40);
In this example I introduced the column id for that matter. Or you can of course just order by your marks or whatever suits your needs.
select
bar
, #total := #total + bar as my_total
from
foo
, (select #total := 0) var_init
order by id
see it working live in this sqlfiddle
As explanation, with this cross joined query
, (select #total := 0) var_init
we initialize our variable holding the running total #total. It's the same as writing
set #total = 0;
select
bar
, #total := #total + bar as my_total
from
foo
order by id;
The rest is self explaining I guess.
You can read more about these type of variables here.
UPDATE (for completeness):
Here are two other possibilities how to solve it without variables. Although I like variables usually better, cause in this one
select
t1.bar
, sum(t2.bar)
from
foo t1
inner join foo t2 on t1.id >= t2.id
group by t1.id;
you end up with a potentially huge temporary table, since you join every row to all previous rows and then calculate the sum.
And in this solution
select
bar
, (select sum(bar) from foo sf where sf.id <= foo.id) as my_total
from
foo;
you have a dependent subquery executed for each row. This is even worse than the previous solution.
I posted those just for completeness and if you really can't use variables (because of creating a view for example).