View with input parameters - sql

Let's say that I have a view with the following structure (and sample data):
Sample_Name Sample_Date Sample_ID
John 01-01-2015 453
Jacob 10-10-2016 777
Jingle 11-11-2017 888
Heimer 12-12-2018 999
Schmidt 07-07-2019 333
If someone specifies the year (i.e. '2019'), I want to return that year and the year prior to it. So the following data set would return:
Sample_Name Sample_Date Sample_ID
Heimer 12-12-2018 999
Schmidt 07-07-2019 333
Is there any way for me to create the view with input parameters (similar to a function), where the user can specify what date they are looking for? Wen the date is specified, the view should return data from that year and the year prior to it. I know with functions you can do something similar but according to my google search, this isn't possible in Oracle :(

It doesn't make sense.
A view is just a stored query. If you want to fetch certain data from it, use a where clause, e.g.
select sample_name, sample_date, sample_id
from your_view
where extract (year from sample_date) >= :par_year - 1;
(where you'd enter 2019 into :par_year, when prompted) (: might need to be replaced by &, depending on a tool you use).

Related

Query with input parameter won't compile as a view

So I am trying to create a view that allows the user (from the front-end) query on it by specifying a specific date (in the form of a varchar/string). The view/query will then return data for the month of the specified date and also data for 13 months prior to it. When I run the following query and enter a valid 'string'/date , I am able to return results successfully. However, when I try to create a view with the same query, i am receiving the following error:
SQL Error: ORA-01027: bind variables not allowed for data definition operations
Below is the query:
SELECT person_name
, person_age
, person_dob
FROM person p
WHERE p.person_dob >= add_months(to_date(:par_date, 'yyyy-mm-dd'), -13);
Here is some sample data:
Person_Name Person_Age Person_DOB
Jon 18 01-01-1990
Jacob 21 09-04-1994
Heidi 28 04-02-2010
mark 30 05-02-2011
Helga 18 03-02-2015
Mike 18 01-02-1992
Larry 18 01-04-1993
I want to return the following result after specify :par_date as '2020-03-02'.
Person_Name Person_Age Person_DOB
Heidi 28 04-02-2010
mark 30 05-02-2011
Helga 18 03-02-2015
You unfortunately cannot do this. The closest you could come would be to create a table function, but that will be much less efficient than just selecting from the table with a 'WHERE' clause.
Ask Tom has a work around, but it is complex, much more work, and potentially very inneficient. Just use a 'WHERE' clause on the view or table
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9536277800346269502

SELECT from 50 columns

I have a table that has many columns around 50 columns that have datetime data that represent steps user takes when he/she do a procedure
SELECT UserID, Intro_Req_DateTime, Intro_Onset_DateTime, Intro_Comp_DateTime, Info_Req_DateTime, Info_Onset_DateTime, Info_Comp_DateTime,
Start_Req_DateTime, Start_Onset_DateTime, Start_Comp_DateTime,
Check_Req_DateTime, Check_Onset_DateTime, Check_Comp_DateTime,
Validate_Req_DateTime, Validate_Onset_DateTime, Validate_Comp_DateTime,
....
FROM MyTable
I want to find the Step the user did after certain datetime
example I want to find user ABC what the first step he did after 2 May 2019 17:25:36
I cannot use case to check this will take ages to code
is there an easier way to do that?
P.S. Thanks for everyone suggested redesigning the database.. not all databases can be redesigned, this database is for one of the big systems we have and it is been used for more than 20 years. redesigning is out of the equation.
You can use CROSS APPLY to unpivot the values. The syntax for UNPIVOT is rather cumbersome.
The actual query text should be rather manageable. No need for complicated CASE statements. Yes, you will have to explicitly list all 50 column names in the query text, you can't avoid that, but it will be only once.
SELECT TOP(1)
A.StepName
,A.dt
FROM
MyTable
CROSS APPLY
(
VALUES
('Intro_Req', Intro_Req_DateTime)
,('Intro_Onset', Intro_Onset_DateTime)
,('Intro_Comp', Intro_Comp_DateTime)
.........
) AS A (StepName, dt)
WHERE
MyTable.UserID = 'ABC'
AND A.dt > '2019-05-02T17:25:36'
ORDER BY dt DESC;
See also How to unpivot columns using CROSS APPLY in SQL Server 2012
The best way is to design your table with your action type and datetime that action was done. Then you can use a simple where clause to find what you want. The table should be like the table below:
ID ActionType ActionDatetime
----------- ----------- -------------------
1492 1 2019-05-13 10:10:10
1494 2 2019-05-13 11:10:10
1496 3 2019-05-13 12:10:10
1498 4 2019-05-13 13:10:10
1500 5 2019-05-13 14:10:10
But in your current solution, you should use UNPIVOT to get what you want. You can find more information in this LINK.

How to get array/bag of elements from Hive group by operator?

I want to group by a given field and get the output with grouped fields. Below is an example of what I am trying to achieve:-
Imagine a table named 'sample_table' with two columns as below:-
F1 F2
001 111
001 222
001 123
002 222
002 333
003 555
I want to write Hive Query that will give the below output:-
001 [111, 222, 123]
002 [222, 333]
003 [555]
In Pig, this can be very easily achieved by something like this:-
grouped_relation = GROUP sample_table BY F1;
Can somebody please suggest if there is a simple way to do so in Hive? What I can think of is to write a User Defined Function (UDF) for this but this may be a very time consuming option.
The built in aggregate function collect_set (doumented here) gets you almost what you want. It would actually work on your example input:
SELECT F1, collect_set(F2)
FROM sample_table
GROUP BY F1
Unfortunately, it also removes duplicate elements and I imagine this isn't your desired behavior. I find it odd that collect_set exists, but no version to keep duplicates. Someone else apparently thought the same thing. It looks like the top and second answer there will give you the UDAF you need.
collect_set actually works as expected since a set as per definition is a collection of well defined and distinct objects i.e. objects occur exactly once or not at all within a set.

How do I use SQL column values as column names in Oracle 11

I have an table something like:
Date | Communication_Type
---------- --------------------
12/10/2011 EMAIL
12/10/2011 WEB
12/10/2011 WEB
11/10/2011 MAIL
11/10/2011 FAX
11/10/2011 FAX
11/10/2011 EMAIL
I want to write a query to display the top two communication types for a certain date, but the communication types are not limited to the ones shown here, they could be one of 100.
Is there a way I could get an output like this, ie for the 11/11/2011
<_top_communication_type_count> | <second_top_communication_type_count>
-------------------------------- --------------------------------------
2 1
where _top_communication_type_count would be the FAX_COUNT in this instance, but for the 12/11/2011 would be WEB_COUNT
Its a bit difficult to explain but hopefully you get what I mean!
I've found examples for mySQL, but not for Oracle.
It isn't possible to use a list of unknown values as column names in Oracle (10g does have pivot but it requires a known list of values). In theory you could do it by querying for unique values first, then building a dynamic query, but it would be a lot of work for marginally useful results.
Below is a solution that returns the data in a normal row-based format (based on #Michael Durrant's answer, modified to work in Oracle):
select *
from (
select communication_type
from communications c
where date = 'the_date'
order by count(c.communication_type)
group by c.communication_type)
where rownum <= 2

Unsure of how to go about this query. Dunno what to call this type of query either please correct this title!

This query is supposed to run with ms access 2003 using SQL. the function JOIN is NOT supported explicitly. implicitly in the WHERE clause is fine...implicity anywhere is fine as long as the word JOIN INNER JOIN Etc is not used.
DayNumnber PastTime
.
.
.
333 Homework
333 TV
334 Date
620 Chores
620 Date
620 Homework
725 Chores
725 Date
888 Internet
888 TV
.
.
.
Hey I would like a query that can Show the most important past time done for each day (TV and internet do not count!) .So importance would be Homework > Chores > Date.So:
DayNumber PastTime
333 Homework
334 Date
620 Homework
725 Chores
Something that might change this problem. Altho all the different past times are listen in a table together. but that was because i appended the table. originally the homework entries. chore entries and date entriess . internet entriess. tv entries. came from different tables.
eg homework 333
homework 620
Is it easier to do it without appending these tables first? I would hopefully like it to be done with the appended table but ya
I was thinking of a mixture of insert. delete... but the hardest part is checking that there is something there for a date a few things and how to put the more important thing done that day . Thank you
Create another table with:
Pri | PastTime
--------------
1 | Homework
2 | Chores
3 | Date
This is a priority list for the items.
Next do:
SELECT MIN(Pri), DayNumber
FROM PastTime_table, Priority_table
WHERE PastTime_table.PastTime = Priority_table.PastTime
GROUP BY DayNumber
This will give you the most important past time for each day. And because TV and Internet are not listed they will not show up.
But it will give you a number, and not the name.
If you had a better SQL you could then join this back to the Priority_table and lookup the name. But I guess you will have to do that part manually.
If you are willing to change the name and call them:
A_Homework
B_Chores
C_Date
instead then you could do (without any extra table):
SELECT MIN(PastTime), DayNumber
FROM PastTime_table
GROUP BY DayNumber
Since it sorts the name alphabetically it will always give you the best one.
You can add a WHERE to remove TV and Internet.