Pivoting in Sybase ASE - sybase-ase

The context of the question is based on the following
ID | Group_Level | Group_Values
1 | Division | Value 1
2 | Department | Value 2
3 | Class | Value 3
should be pivoted into
ID | Division | Department | Class
1 | Value 1 | Value 2 | Value 3
2 | Value 1 | Value 2 | Value 3
Based on many searches and experiments I have done trying pivoting in Sybase ASE, there seems to be only support for pivoting when you know what the values can be.
For example,
select id,
max (case when group_level = 'Division' then Group_Values else null end) Division,
max (case when group_level = 'Department' then Group_Values else null end) Department,
max (case when group_level = 'Class' then Group_Values else null end) Class
from YourTable group by id
works when we know values of group_level. All the other answers I got doesn't work in Sybase ASE and were based on Sybase Anywhere or other DB.
So, Is there a way this can be done more generic when we don't know the values of that field in Sybase-ASE
The example and answer are taken from
Pivoting in Sybase SQL Query?

Related

how to select data that have the same value with sql?

I have a table with three columns, id, name, and value, as shown below. I want to count the average where the id and value columns are the same, how can I do this?
+----+--------+-------+
| id | name | value |
+----+--------+-------+
| 2 | rahmat | 3 |
| 2 | olive | 5 |
| 3 | sari | 3 |
| 3 | ryan | 2 |
| 1 | zaki | 1 |
+----+--------+-------+
Try using this query:
SELECT AVG(value)
FROM table
WHERE id = value
The output from the sample table you gave in your OP would be 1.5, since sari and zaki are the only 2 users whose records have id and value columns which are equal.
according to your question yes you need to use
SELECT AVG(value)
FROM #table
WHERE id = value
I have created a sqlfiddle here
http://sqlfiddle.com/#!3/9eecb7/4105
from the nature of this question I feel you trying to calculate average of values of those rows having same ids. If that's the case I have created another fiddle http://sqlfiddle.com/#!3/9eecb7/4110 where you need to use group by
select id, sum(value)/count(id) as average from #table group by id
Lemme know if it is something you are after or you need something else.

Access 2007 Query to return latest date note from subquery

I have 2 tables joined by ProjectID in Access 2007. Table structure of primary table (A) is like
ProjectID | CustID
1 | 5
2 | 8
I have a secondary table (B) of notes on the ProjectID, structured like
ProjectNotesID | ProjectID | Note | CreateDate
---------------------------------------------------
1 | 1 | Note11 | 1/2/2015
2 | 1 | Note12 | 2/2/2015
3 | 2 | Note21 | 4/8/2015
4 | 2 | Note22 | 3/5/2015
I want to return all of, or part of, Table A, with the latest note of Table B, something like
ProjectID | CustID | Note | CreateDate
------------------------------------------
1 | 5 | Note12 | 2/2/2015
2 | 8 | Note21 | 4/8/2015
I can do (and have done) this with PHP & MySQL, but can't get it to work in Access 2007. I can return the ProjectID and latest Note date by the following query in Access 2007
SELECT ProjectID, Max(CreateDate) AS MaxOfCreateDate
FROM Table B
GROUP BY ProjectID;
I have tried Unique Values, etc., but can't get the results I am looking for.
Thanks!
Pete
I found an answer. First, I changed the query where I got the latest date, and instead got the max ProjectNotesID. The query is ::
SELECT ProjectID, Max(ProjectNotesID) AS MaxOfProjectNotesID
FROM Table B
GROUP BY ProjectID;
I then created a second query combining the above query and Table B, joining Query.MaxOfProjectNotesID <-> TableB.ProjectNotesID, and Query.ProjectID <-> TableB.ProjectID. The second query pulls all values from TableB.

Transposing Rows to Columns

I am trying to come up with a single result set from two tables in a way that I have never done, and I am having a little bit of trouble figuring out how to do it or even what to search for in these forums. Consider the following hypothetical table data:
Table1
----------------------------------
ID | Name
----------------------------------
1 | aa
2 | bb
3 | cc
4 | dd
5 | ee
Table2
----------------------------------
ID | Table1_ID | Value
----------------------------------
1 | 1 | good
2 | 2 | Dumb
3 | 3 | Fat
4 | 4 | Wet
5 | 5 | High
6 | 1 | Thin
7 | 2 | Tall
8 | 3 | Goofy
9 | 4 | Rich
10 | 5 | Funny
I am looking for a query or method that allows me to end up with the following result set:
Code:
aa | bb | cc | dd | ee
---------------------------------------------------------------
good | Dumb | Fat | Wet | High
Thin | Tall | Goofy | Rich | Funny
Essentially, I want the ability to take the list of names from Table1, transpose them into column headers, then put all of Table2's values into their respective columns with the ability to sort on any column. Is this possible?
Of course this can be done in SQL. But it is tricky. As the data is written in the question, you can group by t2.id in groups of 5. After that, the query is just conditional aggregation.
select max(case when t2.table1_Id = 1 then value end) as aa,
max(case when t2.table1_Id = 2 then value end) as bb,
max(case when t2.table1_Id = 3 then value end) as cc,
max(case when t2.table1_Id = 4 then value end) as dd,
max(case when t2.table1_Id = 5 then value end) as ee
from table2 t2
group by cast(t2.id - 1 / 5 as int);
Having values be implicitly related by their ids seems like a really, really bad database design. There should be some sort of entity id that combines them.
You've got two problems here:
1) Using values as column names can't be done in a clean way
2) You want to split table2.value in 2 rows: Which of the values should be on which row? Gordon Linoff uses the table2.id field for this, but if it's auto increment and your data gets some adds/deletes later on that rhythm will get broken.
There's been similar questions before. This one has an answer that gets pretty close:
mysql select dynamic row values as column names, another column as value
Here they generate the string for the query and make a prepared statement out of it.

Join Row to Previous Closest Date Row

Database data:
id | account | date | random_data
1 | 1 | 01/01/2013 | qw
2 | 2 | 05/01/2013 | er
3 | 2 | 09/01/2013 | ty
4 | 1 | 05/01/2013 | ui
5 | 2 | 11/01/2013 | op
6 | 1 | 12/01/2013 | as
Hi, so let's say I want the records starting from 05/01/2013 - note that prev_date for the 1st row still shows an earlier date than 05/01 meaning that the whole table still needs to be searched.
Result data:
account | cur_date | random_data | prev_date | prev_rand_data
1 | 05/01/2013 | ui | 01/01/2013 | qw
1 | 12/01/2013 | as | 05/01/2013 | ui
2 | 05/01/2013 | er | null | null
2 | 09/01/2013 | ty | 05/01/2013 | er
2 | 11/01/2013 | op | 09/01/2013 | ty
So I'm not sure what is the best, most optimized query I could use for this. I'm not opposed to a php solution but not sure how much better that would be. Some ideas I've considered:
Some sort of join on the same table - not sure how though
Sub queries on the select -
select date as cur_date
, (select max(date)
from table
where date < cur_date
group by account)
as prev_date... - this seems like it could be incredibly intensive
Session variables - set a session variable on each row which will be the previous data for the next row e.g.
select date as cur_date
, #prev_date as prev_date
, #prev_date:=date...
Has anyone had any experience with a problem like this and was there a good solution? Are there any positives negatives with any of the ideas I have that could cause problems in the future?
I would use a combination of sql and application code. Since I am not a php programmer, I will only describe the logic to use for the application part.
First the query.
select account, date, random_data
from thetable
where date >= YourDateVariable
union
select account, date, random_data
from thetable join
(select account acc, max(date) maxdate
from thetable
where date <= YourDateVariable
group by account) x on account = acc and date = max(date)
where date <= YourDateVariable
order by account, date
For the application code, do this:
Set a variable called ThisAccount to 0.
Set a row counter variable to 0.
Create an empty 2D array
Start looping through your query results
Put the account value and random data into the first two columns
of the next available row of the array
Compare the account value to the value of the ThisAccount variable.
If they are the same, get the previous date and random data from
the previous row in the array.
Set the ThisAccount variable to the current account value.
Increment your row counter variable
End of loop.

WHERE vs HAVING in generated queries

I know that this title is overused, but it seems that my kind of question is not answered yet.
So, the problem is like this:
I have a table structure made of four tables (tables, rows, cols, values) that I use to recreate the behavior of the information_schema (in a way).
In php I am generating queries to retrieve the data, and the result would still look like a normal table:
SELECT
(SELECT value FROM `values` WHERE `col` = "3" and row = rows.id) as "col1",
(SELECT value FROM `values` WHERE `col` = "4" and row = rows.id) as "col2"
FROM rows WHERE `table` = (SELECT id FROM tables WHERE name = 'table1')
HAVING (col2 LIKE "%4%")
OR
SELECT * FROM
(SELECT
(SELECT value FROM `values` WHERE `col` = "3" and row = rows.id) as "col1",
(SELECT value FROM `values` WHERE `col` = "4" and row = rows.id) as "col2"
FROM rows WHERE `table` = (SELECT id FROM tables WHERE name = 'table1')) d
WHERE col2 LIKE "%4%"
note that the part where I define the columns of the result is generated by a php script. It is less important why I am doing this, but I want to extend this algorithm that generates the queries for a broader use.
And we got to the core problem, I have to decide if I will generate a where or a having part for the query, and I know when to use them both, the problem is my algorithm doesn't and I have to make a few extra checks for this. But the two above queries are equivalent, I can always put any query in a sub-query, give it an alias, and use where on the new derived table. But I wonder if I will have problems with the performance or not, or if this will turn back on me in an unexpected way.
I know how they both work, and how where is supposed to be faster, but this is why I came here to ask. Hopefully I made myself understood, please excuse my english and the long useless turns of phrases, and all.
EDIT 1
I already know the difference between the two, and all that implies, my only dilemma is that using custom columns from other tables, with variable numbers and size, and trying to achieve the same result as using a normally created table implies that I must use HAVING for filtering the derived tables columns, at the same time having the option to wrap it up in a subquery and use where normally, this probably will create a temporary table that will be filtered afterwards. Will this affect performance for a large database? And unfortunately I cannot test this right now, as I do not afford to fill the database with over 1 billion entries (that will be something like this: 1 billion in rows table, 5 billions in values table, as every row have 5 columns, 5 rows in cols table and 1 row in tables table = 6,000,006 entries in total)
right now my database looks like this:
+----+--------+-----------+------+
| id | name | title | dets |
+----+--------+-----------+------+
| 1 | table1 | Table One | |
+----+--------+-----------+------+
+----+-------+------+
| id | table | name |
+----+-------+------+
| 3 | 1 | col1 |
| 4 | 1 | col2 |
+----+-------+------+
where `table` is a foreign key from table `tables`
+----+-------+-------+
| id | table | extra |
+----+-------+-------+
| 1 | 1 | |
| 2 | 1 | |
+----+-------+-------+
where `table` is a foreign key from table `tables`
+----+-----+-----+----------+
| id | row | col | value |
+----+-----+-----+----------+
| 1 | 1 | 3 | 13 |
| 2 | 1 | 4 | 14 |
| 6 | 2 | 4 | 24 |
| 9 | 2 | 3 | asdfghjk |
+----+-----+-----+----------+
where `row` is a foreign key from table `rows`
where `col` is a foreign key from table `cols`
EDIT 2
The conditions are there just for demonstration purposes!
EDIT 3
For only two rows, it seems there is a difference between the two, the one using having is 0,0008 and the one using where is 0.0014-0.0019. I wonder if this will affect performance for large numbers of rows and columns
EDIT 4
The result of the two queries is identical, and that is:
+----------+------+
| col1 | col2 |
+----------+------+
| 13 | 14 |
| asdfghjk | 24 |
+----------+------+
HAVING is specifically for GROUP BY, WHERE is to provide conditional parameters. See also WHERE vs HAVING
I believe the having clause would be faster in this case, as you're defining specific values, as opposed to reading through the values and looking for a match.
See: http://database-programmer.blogspot.com/2008/04/group-by-having-sum-avg-and-count.html
Basically, WHERE filters out columns before passing them to an aggregate function, but HAVING filters the aggregate function's results.
you could do it like that
WHERE col2 In (14,24)
your code WHERE col2 LIKE "%4%" is bad idea so what about col2 = 34 it will be also selected.

Resources