I have a custom z_table containing document id (key), username and two status fields - in progress and completed. My goal is to count how many documents are in progress and completed by the distinct users.
I would like to populate the status fields of the internal table of type Z_table with 1s and 0s as follows and then I could use the aggregate functions to count. For displaying the data I am using class cl_salv_table. Below is an example how my table should look like:
- Doc ID-----User-----In progress-----Completed --
¦ 201 ¦ user1 ¦ 1 ¦ 1 ¦
--------------------------------------------------
¦ 202 ¦ user2 ¦ 1 ¦ 0 ¦
--------------------------------------------------
How could I fill the fields "In progress" and "Completed" with 1s and 0s based by a condition? The condition I know.
Could anybody help me with this please?
Thank you very much!
If I understand the problem well then a simple LOOP and IF condition will solve your problem.
If the username in your internal table is already filled in you will simply go through the table and if the username is the same you will fill in the status with the appropriate value.
SELECT *
FROM Z_TABLE
INTO #DATA(itab)
ORDER BY user. "Sort by user
LOOP AT itab INTO DATA(itab_line).
"If the user is new, append it to the table
IF itab_line-user <> last_user.
APPEND VALUE #( user = itab_line-user
in_progress = itab_line-in_progress
completed = itab_line-completed ) TO result_tab
"If the user is already exists in the table, change the status
ELSE.
ASSIGN result_tab[ user = itab_line-user ] TO FIELD-SYMBOL(<itab_line_by_user>).
<itab_line_by_user>-in_progress = <itab_line_by_user>-in_progress + itab_line-in_progress.
<itab_line_by_user>-completed = <itab_line_by_user>-completed + itab_line-completed.
ENDIF.
"Set the last_user variable
last_user = itab_line-user.
ENDLOOP.
This is just one possible solution out of many.
For example: It is also possible to solve this with the LOOP AT GROUP or REDUCE command.
Related
I have a query as below. The result is always predefined as -
If the query result has 3 events and if the 3rd event has event="delivered" as value then the whole transaction needs to be returned as "COMPLETE".
If the 3rd event is present and event!="delivered" then the status becomes "PENDING"
If the 3rd event is not present at all, then the transaction is marked as ERROR
My Query -
index=myindex OR index=myindex2 uuid=98as786-ffe6-4de1-929y-080e99bc2e6r (status="202") OR (TransactionStatus="PUBLISHED") | append [search index=myindex2 (logMessage="Producer created new event") event="delivered" OR event="processed" serviceName="abc" [search index=myindex uuid=98as786-ffe6-4de1-929y-080e99bc2e6r AND status="SUCCESS" AND serviceName="abc" | top limit=1 headerId | fields + headerId | rename headerId as message_id]]
Result events -
Event1 - 202 Accepted
Event 2 - Adapter Success
Event 3 - delivered or error or processed
My high level dashboard should look like below -
Complete - 6378638
Pending - 2173
Error - 6356
The unique ID will be the UUID on which the count to be performed.
What can be the possible way we can do this - eval ? Lookup ? not sure as I am new to splunk.
Please let me know if more information is needed if I am missing something.
See if this helps. The terminology in your question is a little inconsistent so you may need to adjust the field names in this query.
index=myindex OR index=myindex2 uuid=98as786-ffe6-4de1-929y-080e99bc2e6r ((status="202") OR (TransactionStatus="PUBLISHED")) OR (index=myindex2 (logMessage="Producer created new event") event="delivered" OR event="processed" serviceName="abc") (index=myindex uuid=98as786-ffe6-4de1-929y-080e99bc2e6r AND status="SUCCESS" AND serviceName="abc" )
| stats count, latest(event) as event by headerId
| eval result=case(count=3 AND event="delivered", "COMPLETE", count=3 AND event!="delivered", "PENDING", count!=3, "ERROR", 1=1, "UNKNOWN")
| stats count by result
| table result count
I have a situation in which a table has information like:
First Name | Last Name | Email
-----------+-----------+-----------------
John Doe jd#email.com
Jane Dont jnd#email.com
And I have a user who wants their email added on to both row's emails to looks like:
First Name | Last Name | Email
-----------+-----------+-----------------------------
John Doe jd#email.com;a#email.com
Jane Dont jnd#email.com;a#email.com
Thank you in advance for any help.
To add a#email.com to all rows in your table:
UPDATE Table
SET Email = Email + ';a#email.com'
To update certain rows:
UPDATE t
SET t.Email = t.Email + ';a#email.com'
FROM Table t
WHERE t.FirstName = 'John'
Note: the above query will update all records with the first name of John
Edit ******** Per #destination-data comment:
If you are also trying to add the new email to columns that have NULL value
SET Email = ISNULL(Email, '') + ';a#email.com'
"...Because null plus anything is null." This technique will change the value from NULL to an empty string plus the new value.
The Problem:
I'm working in PostgreSQL 9.0 and I'm having a difficult time figuring out how to tackle the situation where you want to return a specific column value of a certain row for use in a CASE WHEN THEN statement.
I want to basically go in and set the value of table A: someRow's someColumn value, equal to the value of table B: row X's column A value, given the value of row X's column B. (More detail in "Backround Info" if needed to understand the question)
This is what I want to do (but don't know how):
Update tableA
Set someColumn
CASE WHEN given_info_column = 'tableB: row X's column B value'
THEN (here I want to return row X's column A value, finding row X using the given column B value)
ELSE someColumn END
Background Info: (Optional, for clarification)
Imagine that there is a user activity table, and a device table in an already existing database, with already existing activity performed strings that exist throughout to codebase you are working in: (for example)
User_Activity:
id (int) | user_name (string) | activity_preformed (string) | category (string)
---------|-----------------------|----------------------------------------|------------------
1 | Joe Martinez | checked out iphone: iphone2 | dvc_activity
2 | Jon Shmoe | uploads video from device: (id: 12345) | dvc_activity
3 | Larry David | goes to the bathroom |other_activity
Device:
seq (int)| device_name (string) | device_srl_num (int) | device_status (string)|
---------+-----------------------+----------------------+-----------------------+
1 | iphone1 | 12344 | available
2 | iphone2 | 12345 | checked out
3 | android1 | 23456 | available
Your assignment from your boss is to create a report that shows one table with all device activity, like so:
Device Activity Report
(int) (int) (string) (string) (string) (int) (string)
act_seq |usr_id | usr_name | act_performed | dvc_name | dvc_srl_num | dvc_status
---------+-------+--------------+---------------------------------------+-----------+-------------+------------
1 |1 | Joe Martinez | Checked out iphone: iphone2 | iphone2 | 12345 | checked out
2 |2 | John Shmoe | uploads video from device: (id: 12345)| android1 | 23456 | available
For the purposes of this question, this has to be done by adding a new column to the user activity table called dvc_seq which will be a foreign key to the device table. You will create a temporary table by querying from the user activity table and joining the two where User_Activity (dvc_seq) = Device (seq)
This is fine and will work great for new entries into the User_Activity table, which will record a dvc_seq linking to the associated device if the activity involves a device.
The problem is that you need to go in and fill in values for the new dvc_seq column in the User_Activity table for all previous entries relating to devices. Since the previous programmers decided to specify which device in the activity_performed column using the serial number certain times and the device names other times, this presents an interesting problem, where you will need to derive the associated Device seq number from a device, given its name or serial number.
So once again, what I want to do: (using this example)
UPDATE User_Activity
SET dvc_seq
CASE WHEN activity_performed LIKE 'checked out iphone:%'
THEN (seq column of Device table)
WHERE (SELECT 1 FROM Device WHERE device_name = (substring in place of the %))
ELSE dvc_seq (I think this would be null since there would be nothing here yet)
END
Can any of you help me accomplish this?? Thanks in advance for all responses and advice!
The query below uses an update-join to update the sequence number when the serial number or the name is contained within the activity_performed
UPDATE UserActivity
SET a.dvc_seq = b.seq
FROM UserActivity AS a
JOIN devices b
ON UserActivity.activity_performed LIKE '%from device: (id: ' || b.serial_num || '%'
OR UserActivity.activity_performed LIKE '%: ' || b.name || '%'
Just an additional update on how to speed up this code based off of the correct answer given by #FuzzyTree (this would only work for the serial number, which has a standard length, and not for the device name which could be many different sizes)
Because of the LIKE used in the join, the query runs very slow for large databases. an even better solution would utilize the postgres substring() and position() functions and join the tables on the serial number like so:
UPDATE UserActivity
SET a.dvc_seq = b.seq
FROM UserActivity AS a
JOIN devices b
ON b.serial_num =
substring(activity_performed from position('%from device: (id: ' in activity_performed)+(length of the string before the plus so that position returns the start position for the serial number)) for (lengthOfSerialNumberHere))
WHERE UserActivity.activity_performed LIKE '%from device: (id: ' || b.serial_num || '%';`
In postgresql you can't do a complex CASE expresion like
CASE WHEN activity_performed LIKE 'checked out iphone:%'
only
CASE WHEN 1, 2
The best you can do is create a function
UPDATE User_Activity
SET dvc_seq = getDeviceID(User_Activity.activity_preformed);
Here you can do IF, CASE much easier
CREATE OR REPLACE FUNCTION getDeviceID(activity text)
RETURNS integer AS
$BODY$
DECLARE
device_name text;
device_id integer;
BEGIN
-- parse the string activity
/* this part is pseudo code
set device_id;
IF (device_id is null)
set device_name;
search for device_id using device_name;
set device_id;
*/
RETURN device_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION get_box(text)
OWNER TO postgres;
I have two tables, one contains user data and the other contains user ranking information (points needed for the promotion)
Let's say that the user table looks like this:
login | ArticlePoints | PhotoPoints | StageId
and the user ranking information table looks like this:
StageId | StageName | MinimumPoints
and the user information table might contain data like this:
1 | Beginner | 100
2 | Advanced | 200
3 | Expert | 300
What I would like to have is a procedure which does add user points and check whether it is enough for the ranking promotion. Right now I do it like this:
I do have a function which does check "manually" whether the user points is between 100 and 200 and then it does set the user stage = 2, id it's more it check whether it's between 200 and 300 etc.
Stored procedure which does update users set stage = MYFUNCTION from the point 1.
The thing is that it's not a good solution, right now it is not ready for the easy updates(I can't just add Super Expert with minimum 400 points, I'd need to edit the function).
I am trying to prepare a better solution for this problem but I have no idea how to "connect" both tables.
Write an UPDATE query that returns the StageID for the calculated values, something like:
UPDATE t1
SET t1.StageID =
(SELECT TOP 1 StageID
FROM [RANKING_TABLE] t2
WHERE t1.ArticlePoints + t1.PhotoPoints >= t2.MinimumPoints
ORDER BY t2.MinimumPoints DESC)
FROM [USER_TABLE] t1
So if the USER has 250 points in total, Beginner and Advanced would be achieved, using the TOP 1 and the ORDER BY t2.MinimumPoints DESC, would select the highest Stage.
I feel like this is a pretty basic SQL question but I am having trouble searching for the answer.
Essentially the logic I want to write in my SQL statement is this.
When doing an update on a row instead of just blanking out the data there add it together.
so if I have a row "9/19/13" | 0 | 1 | 0 and now I want to update that row with this entry "9/19/13" | 0 | 1 | 0 I get "9/19/13" | 0 | 2 | 0.
My current update command looks like so.
UPDATE entries(Date, John, Mark, Casey) SET (#Date, #John, #Mark, #Casey) WHERE(Date = #Date);
I could easily do it in my actual code where I would retrieve the entry increment it then just do a regular update, but I feel like it should be possible to to do it with straight SQL, and would be cleaner.
Is this what you mean?
-- #John, #Mark, #Casey are set in advance
UPDATE entries(Date, John, Mark, Casey)
SET (#Date, John + #John, Mark + #Mark, Casey + #Casey)
WHERE (Date = #Date);
calling update is just setting the values in the db to be the values you pass in, not the existing value added (in the case of numbers) to the value you're updating with.
it would be much simpler to just increment the value before update as you already have it.