I have 4 tables, from which i select data with help of joins in select query...I want a serial no.(row number) per record as they are fetched. first fetched record should be 1, next 2 and so on...
In oracle the equiavelent in RowNum.
The answer by Brettski is ASP flavored and would need a lot of editing.
SELECT DCOUNT("YourField","YourTable","YourField <= '" & [counter] & "'")
AS RowNumber,
YourField as counter FROM YourTable;
Above is your basic syntax. You are likely to find this runs very slow. My typical solution is a bucket table with Autonumber field. That seems kludgy, but it gives me control and probably in this case it allows speed.
Using a sorted Make Table Query in Access, I use the following (wouldn't work if you look at the Query, as that would increment the number when you don't want it to)....
setRowNumber 'resetting increment before running SQL
DoCmd.RunSQL ... , rowNumber([Any Field]) AS ROW, ...
'Increment Number: Used to create temporary sorted Table for export
Private ROWNUM As Long
'dummyField: must take an input to update in Query
Public Function rowNumber(ByVal dummyField As Variant, Optional ByVal incBy As Integer = 1) As Long
ROWNUM = ROWNUM + incBy 'increments before value is returned
rowNumber = ROWNUM
End Function
Public Function setRowNumber(Optional ByVal setTo As Long = 0) As Long
ROWNUM = setTo
setRowNumber = ROWNUM
End Function
With the following table
SET NOCOUNT ON
CREATE TABLE people
(
firstName VARCHAR(32),
lastName VARCHAR(32)
)
GO
INSERT people VALUES('Aaron', 'Bertrand')
INSERT people VALUES('Andy', 'Roddick')
INSERT people VALUES('Steve', 'Yzerman')
INSERT people VALUES('Steve', 'Vai')
INSERT people VALUES('Joe', 'Schmoe')
You can use a sub query to create the counting row:
SELECT
rank = COUNT(*),
a.firstName,
a.lastName
FROM
people a
INNER JOIN people b
ON
a.lastname > b.lastname
OR
(
a.lastName = b.lastName
AND
a.firstName >= b.firstName
)
GROUP BY
a.firstName,
a.lastName
ORDER BY
rank
The problem with this method is that the count will be off if there are duplicates in your results set.
This article explains pretty well how to add a row counting column to your query.
Related
I am trying to reduce the number of queries my application uses to build the dashboard and so am trying to gather all the info I will need in advance into one table. Most of the dashboard can be built in javascript using the JSON which will reduce server load doing tons of PHP foreach, which was resulting in excess queries.
With that in mind, I have a query that pulls together user information from 3 other tables, concatenates the results in JSON group by family. I need to update the JSON object any time anything changes in any of the 3 tables, but not sure what the "right " way to do this is.
I could set up a regular job to do an UPDATE statement where date is newer than the last update, but that would miss new records, and if I do inserts it misses updates. I could drop and rebuild the table, but it takes about 16 seconds to run the query as a whole, so that doesn't seem like the right answer.
Here is my initial query:
SET group_concat_max_len = 100000;
SELECT family_id, REPLACE(REPLACE(REPLACE(CONCAT("[", GROUP_CONCAT(family), "]"), "\\", ""), '"[', '['), ']"', ']') as family_members
FROM (
SELECT family_id,
JSON_OBJECT(
"customer_id", c.id,
"family_id", c.family_id,
"first_name", first_name,
"last_name", last_name,
"balance_0_30", pa.balance_0_30,
"balance_31_60", pa.balance_31_60,
"balance_61_90", pa.balance_61_90,
"balance_over_90", pa.balance_over_90,
"account_balance", pa.account_balance,
"lifetime_value", pa.lifetime_value,
"orders", CONCAT("[", past_orders, "]")
) AS family
FROM
customers AS c
LEFT JOIN accounting AS pa ON c.id = pa.customer_id
LEFT JOIN (
SELECT patient_id,
GROUP_CONCAT(
JSON_OBJECT(
"id", id,
"item", item,
"price", price,
"date_ordered", date_ordered
)
) as past_orders
FROM orders
WHERE date_ordered < NOW()
GROUP BY customer_id
) AS r ON r.customer_id = c.id
where c.user_id = 1
) AS results
GROUP BY family_id
I briefly looked into triggers, but what I was hoping for was something like:
create TRIGGER UPDATE_FROM_ORDERS
AFTER INSERT OR UPDATE
ON orders
(EXECUTE QUERY FROM ABOVE WHERE family_id = orders.family_id)
I was hoping to create something like that for each table, but at first glance it doesn't look like you can run complex queries such as that where we are creating nested JSON.
Am I wrong? Are triggers the right way to do this, or is there a better way?
As a demonstration:
DELIMITER $$
CREATE TRIGGER orders_au
ON orders
AFTER UPDATE
FOR EACH ROW
BEGIN
SET group_concat_max_len = 100000
;
UPDATE target_table t
SET t.somecol = ( SELECT expr
FROM ...
WHERE somecol = NEW.family_id
ORDER BY ...
LIMIT 1
)
WHERE t.family_id = NEW.family_id
;
END$$
DELIMITER ;
Notes:
MySQL triggers are row level triggers; a trigger is fired for "for each row" that is affected by the triggering statement. MySQL does not support statement level triggers.
The reference to NEW.family_id is a reference to the value of the family_id column of the row that was just updated, the row that the trigger was fired for.
MySQL trigger prohibits the SQL statements in the trigger from modifying any rows in the orders table. But it can modify other tables.
SQL statements in a trigger body can be arbitrarily complex, as long as its not a bare SELECT returning a resultset, or DML INSERT/UPDATE/DELETE statements. DDL statements (most if not all) are disallowed in a MySQL trigger.
I am facing an issue with using a variable in the WHERE clause of a mysql query. I tried searching google but could not find any answer.
At the start of a MySQL script, I assign some value into a variable and then use that variable at multiple places inside the query. At one specific subquery, if I use the variable, the query keeps on running but if I use the constant value of the variable instead, the query runs in a second.
Please have a look at the below example. Here I am using a variable #maxid in WHERE clause
set #maxid2 = '1001-a';
select distinct
dc.db_date,
dc.year_month,
dc.year,
dc.week,
dc.day,
dc.dayofweek - 1 as DayOfWeek,
em.ID as EmployeeID,
concat_ws(' ', em.`FirstName`, `LastName`) as EmployeeName
from
datavis_cal dc
cross join
employees_data em ON em.ID = #maxid2
and dc.db_date >= (select
min(assigndate)
from
attendance_data
where
ID = #maxid2)
and db_date <= curdate()
and em.DeptID = (select distinct
DeptID
from
users
where
username = 'demo')
This code keeps on running and I have to cancel the query. Now have a look at the below query. It's the same query but here instead of the variable, I am using the constant value of the variable. I have replaced the variable #maxid2 with its value '1001-a' in the script:
set #maxid2 = '1001-a';
select distinct
dc.db_date,
dc.year_month,
dc.year,
dc.week,
dc.day,
dc.dayofweek - 1 as DayOfWeek,
em.ID as EmployeeID,
concat_ws(' ', em.`FirstName`, `LastName`) as EmployeeName
from
datavis_cal dc
cross join
employees_data em ON em.ID = '1001-a'
and dc.db_date >= (select
min(assigndate)
from
attendance_data
where
ID = '1001-a')
and db_date <= curdate()
and em.DeptID = (select distinct
DeptID
from
users
where
username = 'demo')
So my question is, what could the variable possibly be doing to the script that it keeps on running but the value of the variable gives result in a second?
Please let me know if I need to explain this more. I have tried many solutions and also searched google but could not find any answer for this.
Try to put the value assignment inside your query:
select aCol
from myTable, (SELECT #value := 2) as a
where aCol = #value;
This way my MariaDB is able to use an index on column 'aCol'
I'm getting 01427. 00000 - "single-row subquery returns more than one row" error while executing below procedure. the issue , what i believe , is in subquery
SELECT paymentterm FROM temp_pay_term WHERE pid = d.xProject_id
but how can i get rid of it.Now, i have added the complete code. please check and let me know the wrong tell me if more info. is to be provided.
CREATE OR REPLACE PROCEDURE paytermupdate IS
recordcount INT;
vardid NUMBER(38);
varpaymentterm VARCHAR2(200 CHAR);
BEGIN
recordcount := 0;
SELECT COUNT(1) INTO recordcount
FROM temp_pay_term;
IF recordcount > 0 THEN
FOR x IN (SELECT DISTINCT r.ddocname
FROM temp_pay_term p, docmeta d, revisions r
WHERE TO_CHAR(p.pid) = d.xproject_id AND r.did = d.did )
LOOP
SELECT MAX(did) INTO vardid
FROM revisions r
WHERE r.ddocname = x.ddocname
GROUP BY r.ddocname;
UPDATE docmeta d
SET paymentterm = (
SELECT paymentterm
FROM temp_pay_term
WHERE pid = d.xproject_id
)
WHERE d.did = vardid;
INSERT INTO documenthistory (dactionmillis, dactiondate, did, drevclassid,
duser, ddocname, daction, dsecuritygroup, paymentterm)
SELECT
to_number(TO_CHAR(systimestamp, 'FF')) AS dactionmillis,
TRUNC(systimestamp, 'dd') AS dactiondate,
did,
drevclassid,
'sysadmin' AS duser,
ddocname,
'Update' AS daction,
dsecuritygroup,
paymentterm
FROM revisions
WHERE did = vardid;
END LOOP;
COMMIT;
END IF;
END paytermupdate;
Do you use something like
select x,y,z, (subquery) from ?
If you are getting ORA-01427 you should think how to make filter conditions in your subquery more restrictive, and these restrictions should be business reasonable, not just simply "and rownum <=1".
As you want to update a record through that sub query you should put more filter conditions in it. You can decide on the filter conditions on the basis of the value you want to update in the table in outer query. If there are more values which satisfy the condition (which I do not believe is ideal but just in case) then rownum <=1 would suffice.
Two basic options come to mind. I'll start with the simplest.
First, add distinct to the subquery.
SET paymentterm =
(SELECT distinct paymentterm
FROM temp_pay_term
WHERE pid = d.xProject_id
)
Second, if you're receiving multiple distinct values from the subquery, then you will either have to (a) rework your script to not use a subquery or (b) limit values returned (as #Baljeet suggested) using more filter criteria or (c) pick which of the multiple distinct values you want using an aggregate function.
Using the aggregate method, I'm guessing PaymentTerm is a number of months or years? Even if it's a n/varchar field (i.e., "6 months"), you can still use the MIN() and MAX() aggregates (or at least you can in t-sql). If it's a numeric field, you could also use average. You'll have to figure out which works best for your business needs.
I have 2 tables: tbl_taxclasses, tbl_taxclasses_regions
This is a one to many relationship, where the main record ID is classid.
I have a column inside the first table called regionscount
So, I create a Tax Class, in table 1. Then I add regions/states in table 2, assigning the classid to each region.
I perform a SELECT statement to count the regions with that same classid, and then I perform an UPDATE statement on tbl_taxclasses with that number. I update the regionscount column.
This means I'm writing 2 queries. Which is fine, but I was wondering if there was a way to do a SELECT statement inside the UPDATE statement, like this:
UPDATE `tbl_taxclasses` SET `regionscount` = [SELECT COUNT(regionsid) FROM `tbl_taxclasses_regions` WHERE classid = 1] WHERE classid = 1
I'm reaching here, since I'm not sure how robust MySQL is, but I do have the latest version, as of today. (5.5.15)
You could use a non-correlated subquery to do the work for you:
UPDATE
tbl_taxclasses c
INNER JOIN (
SELECT
COUNT(regionsid) AS n
FROM
tbl_taxclasses_regions
GROUP BY
classid
) r USING(classid)
SET
c.regionscount = r.n
WHERE
c.classid = 1
Turns out I was actually guessing right.
This works:
UPDATE `tbl_taxclasses`
SET `regionscount` = (
SELECT COUNT(regionsid) AS `num`
FROM `tbl_taxclasses_regions`
WHERE classid = 1)
WHERE classid = 1 LIMIT 1
I just needed to replace my brackets [] with parenthesis ().
This time I have a MySQL question, I'm trying to create a stored procedure which will execute a prepared statement, the goal is to get a ranged list from a table("order_info"), the list is divided by "pages", each page is determined by a record count and should be ordered using a particular field sorted either 'ASC' or 'DESC', each record represents an "order" the catch here is that the procedure returns the orders of a particular group, the the order is associated to a user which belongs to a group. Here's what I've done so far:
CREATE DEFINER=`root`#`%` PROCEDURE `getGroupOrders`(IN grp INT,
IN page INT,
IN count INT,
IN ord TINYINT,
IN srt VARCHAR(4)
)
BEGIN
PREPARE prepGroupOrders FROM
"SELECT oi.* FROM `dbre`.`order_info` oi
INNER JOIN `dbre`.`users` usr
ON oi.`username` = usr.`username` AND usr.`id_group` = ?
ORDER BY ? ? LIMIT ?, ?";
SET #g := grp;
SET #cnt := count;
SET #start := #page*count ;
SET #orderBy := ord;
SET #sortBy := srt;
EXECUTE prepGroupOrders USING #g,#orderBy,#sortBy,#start,#cnt;
END
I get a syntax error when executing this, even though the editor does not higlight any errors and lets me save the procedure,I think that one of the follwing may be happening:
I am incorrectly usng the `ASC` or `DESC` since it is a SQL reserved word.
I read somewhere that Prepared statement are for only ONE SQL query, and since I have nested queries it can't be done.
I've tested this standard query:
SELECT oi.* FROM `dbre`.`order_info` oi
INNER JOIN `dbre`.`users` usr
ON oi.`username` = usr.`username` AND usr.`id_group` = 1
ORDER BY `status` DESC LIMIT 5, 10;
And it gives me the results I want. SO how would I design the procedure?
Any help is truly appreciated.
This may not necessarily solve your issue but, you can probably clean that query up a bit, eliminate the subquery and get something that should perform a little better.
SELECT oi.*
FROM `dbre`.`order_info` oi
INNER JOIN `dbre`.`users` u
ON oi.username = u.username
AND u.id_group = 1
ORDER BY `status` DESC
LIMIT 5, 10;