How to use a variable as a column name in DolphinDB? - sql

To simplify my question: start with the following table in DolphinDB:
t=table(1 2 3 as x, 4 5 6 as y)
I would like to select a column from the table, but I prefer to assign the column to choose in a separate statement. I tried the following:
colName= x
select colName from t
and
colName="x"
select colName from t
neither works. I am sure there is a way to do this in DolphinDB. Could someone point out where to look at in the manual? Thanks!

You can take a look at the part about metaprogramming in DolphinDB's manual:
https://www.dolphindb.com/help/Metaprogramming.html
For your question, try this:
colName= "x"
sql(select=sqlCol(colName), from=t).eval()

Related

New column based on list of values SQL

I am new to SQL and working on a database that needs a binary indicator based on the presence of string values in a column. I'm trying to make a new table as follows:
Original:
Indicator
a, b, c
c, d, e
Desired:
Indicator
type
a, b, c
1
c, d, e
0
SQL code:
SELECT
ID,
Contract,
Indicator,
CASE
WHEN Indicator IN ('a', 'b')
THEN 1
ELSE 0
END as Type
INTO new_table
FROM old_table
The table I keep creating reports every type as 0.
I also have 200+ distinct indicators, so it will be really time-consuming to write each as:
CASE
WHEN Indicator = 'a' THEN '1'
WHEN Indicator = 'b' THEN '1'
Is there a more streamlined way to think about this?
Thanks!
I think the first step is to understand why your code doesn’t work right now.
If your examples of what’s Indicator column are literally the strings you noted (a, b, c in one string and c, d, e in another) you should understand that your case statement is saying “I am looking for an exact match on the full value of Indicator against the following list -
The letter A or
The letter B
Essentially- you are saying “hey SQL, does ‘a,b,c’ match to ‘a’? Or does ‘a,b,c’ match to ‘b’. ?”
Obviously SQL’s answer is “these don’t match” which is why you get all 0s.
You can try wildcard matching with the LIKE syntax.
Case when Indicator like ‘%a%’ or Indicator like ‘%b%’ then 1 else 0 end as Type
Now, if the abc and cde strings aren’t REALLY what’s in your database then this approach may not work well for you.
Example, let’s say your real values are words that are all slapped together in a single string.
Let’s say that your strings are 3 words each.
Cat, Dog, Man
Catalog, Stick, Shoe
Hair, Hellcat, Belt
And let’s say that Cat is a value that should cause Type to be 1.
If you write: case when Indicator like ‘%cat%’ then 1 else 0 end as Type - all 3 rows will get a 1 because the wildcard will match Cat in Catalog and cat in Hellcat.
I think the bottom line is that unless your Indicator values really are 3 letters and your match criteria is a single letter, you very well could be better off writing a 200 line long case statement if you need this done any time soon.
A better approach to consider (depending on things like are you going to have 300 different combinations a week or month or year from now?)
If yes, wouldn’t it be nice if you had a table with a total of 6 rows - like so?
Indicator | Indictor_Parsed
a,b,c | a
a,b,c | b
a,b,c | c
c,d,e | c
c,d,e | d
c,d,e | e
Then you could write the query as you have it case when Indicator_Parsed in (‘a’, ‘b’) then 1 else 0 end as Type - as a piece of a more verbose solution.
If this approach seems useful to you, here’s a link to the page that lets you parse those comma-separated-values into additional rows. Turning a Comma Separated string into individual rows
ON mysql/sql server You can do it as follows :
insert into table2
select Indicator,
CASE WHEN Indicator like '%a%' or Indicator like '%b%' THEN 1 ELSE 0 END As type
from table1;
demo here
You can use the REGEXP operator to check for presence of either a, b or both.
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
If you need that into a table, you either create it from scratch
CREATE your_table AS
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
or you insert values in it:
INSERT INTO your_table
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
Check the demo here.

SQL, incrementing column value returned from SELECT query

SELECT x, y, z FROM table_one
WHERE y='asd'
ORDER BY z ASC;
Hi, I'm querying my database using the query above, upon the return of the query I'd like to increment z by 1 (not update it but just increment it so it shows in the result). I don't want to do an Update statement, this is just temporary and should only be visible in the query result.
How would I go about doing this? It's for a school assignment. I've tried to use REPLACE without any success. What works is changing z to z+1 but then the column name changes to ?column? instead of z.
Any help would be appreciated!
You need add column alias:
SELECT x, y, z + 1 AS z -- here
FROM table_one
WHERE y='asd'
ORDER BY z ASC;

HANA concat rows

I use SAP-HANA database. I have a simple 2 column table whose columns are number, name, noodles, fish . The rows are these:
number name noodles fish
1 tom x
1 tom x
1 jack
2 jack x
I would like to group the rows by the id, and concatenate the names into a field, and thus obtain this:
number name noodles fish
1 tom x x
2 jack x
Can you please tell me how we can perform this operation in sap-hana? Thanks in advance.
Well, you did not really concatenate the names, but instead kept the same ones (if you would have concatenated the names as well, you would get something like jackjack in your result). I guess your x's indicate some sort of ABAP-style flags.
In any case, you would do this with grouping. This is a completely non-HANA thing (you can use the same basic SQL for any DB). You can group against several columns. All other columns that you want to select must be used in an aggregated expression (e.g. a SUM, MAX, COUNT, etc.).
To get the output from your question, I wrote the following code:
SELECT "ID", "NAME", MAX("FISH"), MAX("NOODLES")
FROM #TEST GROUP BY "ID", "NAME";
And got the same output as you. I used the MAX function based on the following assumption: you would want to get X if there is any X in the "concatenated" (aggregated) rows in that column. You get nothing / space if all the "concatenated" rows have space in them.

SQL list only unique / distinct values

I have a table which contains geometry lines (ways).There are lines that have a unique geometry (not repeating) and lines which have the same geometry (2,3,4 and more). I want to list only unique ones. If there are, for example, 2 lines with the same geometry I want to drop them. I tried DISTINCT but it also shows the first result from duplicated lines. I only want to see the unique ones.
I tried window function but I get similar result (I get a counter on first line from the duplicating ones). Sorry for a newbie question but I'm learning :) Thanks!
Example:
way|
1 |
1 |
2 |
3 |
3 |
4 |
Result should be:
way|
2 |
4 |
That actually worked. Thanks a lot. I also have other tags in this table for every way (name, ref and few other tags) When I add them to the query I loose the segregation.
select count(way), way, name
from planet_osm_line
group by way, name
having count(way) = 1;
Without "name" in the query I get all unique values listed but I want to keep "name" for every line. With this example I stilll get all the lines in the table listed.
To expound on #Nithila answer:
select count(way), way
from your_table
group by way
having count(way) = 1;
You first calculate the rows you want, and then search for the rest of the fields. So the aggregation doesnt cause you problems.
WITH singleRow as (
select count(way), way
from planet_osm_line
group by way
having count(way) = 1
)
SELECT P.*
FROM planet_osm_line P
JOIN singleRow S
ON P.way = S.way
you can group by way and while taking the data out check the count=1.It will give non duplicating data.
#voyteck
As I understood your question you need to get only non duplicating records of way column and for each row you need to show the name is it
If so, you have to put all the column in select statement, but no need to group by all the columns.
select count(way), way, name
from planet_osm_line
group by way
having count(way) = 1;

Comma delimited values sql

From my research online I have discovered two answers to this question which I am trying to stay away from.
I cannot modify the table or add a new table because the software is third party and needs the table to remain unmodified.
I am trying to stay away from using temporary tables or extra user defined functions.
Here is my issue.
There is a column in the database that is a list of comma-delimited numbers representing days of the week, i.e. (1,2,4,5,7).
I am trying to find a way to read that data and find out if there are any rows where that column represents days that are 3 consecutive days.
It should return anything with
1,2,3
2,3,4
3,4,5
5,6,7
1,,,,,6,7
1,2,,,,,7
But if the column has 1,2,3,4 it should not return twice. There are a lot of rows that have 2,3,4,5,6 and any solution I've come up with will return that 3 times.
Preferably, I would like to create a stored procedure to pass in a number and look for that number of consecutive days. So if 5 is passed in, it will look for anything that is marked for 5 consecutive days.
Is there another option other than using extra tables? If so can you show me how to do make this work? I am not new to SQL but there are a lot of more advanced querying techniques I am not familiar with.
The following brute force method will work in all databases:
select (case when col like '%1%' and col like '%2%' and col like '%3%' then 1
when col like '%2%' and col like '%3%' and col like '%4%' then 1
when col like '%3%' and col like '%4%' and col like '%5%' then 1
when col like '%4%' and col like '%5%' and col like '%6%' then 1
when col like '%5%' and col like '%6%' and col like '%7%' then 1
when col like '%6%' and col like '%7%' and col like '%1%' then 1
when col like '%7%' and col like '%1%' and col like '%2%' then 1
else 0
end) as HasThreeConsecutiveDays
It returns a 0/1 flag if three days are consecutive.
So if 5 is passed in, it will look for anything that is marked for 5 consecutive days.
You won't be able to do that without dynamic sql, because you want to support wrapping from 7 back to 1. I could write a query that would do it for you in a single statement if you didn't care about wrapping from the end of the week back to the beginning, but with that requirement I don't see how to do it without building a dynamic sql string in the procedure, which I don't have time to play with right now (maybe someone else will take that idea and run with it).
With that option defeated for now, I can do this instead:
WHERE
( col like '1,2,3%'
OR col like '%2,3,4%'
OR col like '%3,4,5%'
OR col like '%4,5,6%'
OR col like '%5,6,7'
OR col like '1%6,7'
OR col like '1,2%7'
)
This should be better than checking individual numbers as shown in another answer, because there are fewer pattern matches to complete. However, it only works if we can guarantee the sort order. We also need to know in advance how the commas are spaced between numbers, but we can fix that issue if necessary by replacing all commas and/or spaces with an empty string (and adjusting the patterns accordingly).
One more thought here: I realized that I can support a day count argument, if you can manage sneaking an additional table into the db somewhere. The table would look something like this:
create Table DayPatterns (Days int, Pattern varchar(13) )
and the data in the table would look like this:
1 1%
1 %2%
1 %3%
...
2 1,2%
2 %2,3%
2 %3,4%
2 %4,5%
...
2 1%7
...
3 1,2,3%
3 %2,3,4%
...
3 1%6,7
3 1,2%7
...
7 1,2,3,4,5,6,7
Hopefully you get the idea on how to fill that out. With that table in hand, you can JOIN against the table with a query like this:
INNER JOIN DayPatterns p ON p.Days = #ConsecutiveDays AND col LIKE p.Pattern
The key to making that work (aside from needing to be able to create that table somewhere) is also doing a GROUP BY on the correct columns. Otherwise, you'll end up with the same problem you have right now, where matching multiple possible consecutive day patterns will duplicate your results.
Finally, of course you know that most any schema that includes csv data is broken, but since you can't seem to fix this, hopefully one of these ideas will help.