I am looking for a way to iterate over result set that has columns id1, id2 and pass the resultset column values to be used in inner query as shown below.
Variables of resultset
column1
column2
Eg:
select * from months cross join (select column1 AS "id1",column2 AS "id2")
Select "GEOGRAPHY" from mytable WHERE id1 = column1 and id2 = column2
However when i execute the stored procedure , i encounter following error. Any pointers much appreciated . Thank you
Error:
Execution error in stored procedure TEST_PROC_STMT: SQL compilation error: error line 8 at position 81 invalid identifier 'COLUMN2' At Snowflake.execute, line 14 position 10
Full Query
create or replace procedure TEST_PROC_STMT()
returns varchar not null
language javascript
EXECUTE AS CALLER
as
$$
var distinct_sql_command = "select distinct id1, id2 from mytable ";
var statement1 = snowflake.createStatement( {sqlText: distinct_sql_command} );
var result_set1 = statement1.execute();
// Loop through the results, processing one row at a time...
while (result_set1.next()) {
var column1 = result_set1.getColumnValueAsString(1);
var column2 = result_set1.getColumnValueAsString(2);
snowflake.execute( {sqlText: `
INSERT INTO mytable("GEOGRAPHY")(
Select * from (
with months as (
select dateadd(month, seq4(), '2020-02-01') "REPORTING MONTH" from table (generator(rowcount => 12))
), months_ids as (
select * from months cross join (select column1 AS "id1",column2 AS "id2")
) ,
event_months as (
Select * from (Select *,ROW_NUMBER() OVER (PARTITION BY id1,id2 ORDER BY "REPORTING MONTH") As rn FROM mytable) Where rn =1
) ,
final as (
select "REPORTING MONTH",id1,id2
, (select array_agg("GEOGRAPHY") within group (order by "REPORTING MONTH" desc) from mytable where a."REPORTING MONTH">="REPORTING MONTH" and a.id1=id1
from months_ids a order by "REPORTING MONTH"
)
Select a."GEOGRAPHY" from final a left join event_months b on a.id1=b.id1 and a.id2 = b.id2 where a."REPORTING MONTH" > b."REPORTING MONTH"
Except
Select "GEOGRAPHY" from mytable WHERE id1 = column1 and id2 = column2
)
)
`});
}
return "success";
$$
;
CALL TEST_PROC_STMT();
There are at least two problems with the code. First, "var" defines a variable, which is a one-time operation. In this case it needs to be moved out of the while loop:
// Loop through the results, processing one row at a time...
while (result_set1.next()) {
var column1 = result_set1.getColumnValueAsString(1);
var column2 = result_set1.getColumnValueAsString(2);
This is an easy fix:
// Loop through the results, processing one row at a time...
var column1;
var column2;
while (result_set1.next()) {
column1 = result_set1.getColumnValueAsString(1);
column2 = result_set1.getColumnValueAsString(2);
The other problem is the code specifies "column2" as a literal column name in the SQL, not a variable. You can tell this because the error message uppercased the variable name, so Snowflake is looking for "COLUMN2" and can't find it. There's also a use of "column1" that appears it should be a replacement variable.
You can fix that by making it a replacement variable. Change these two lines:
select * from months cross join (select column1 AS "id1",column2 AS "id2")
... and this one ...
Select "GEOGRAPHY" from mytable WHERE id1 = column1 and id2 = column2
To this:
select * from months cross join (select ${column1} AS "id1", ${column2} AS "id2")
... and this ...
Select "GEOGRAPHY" from mytable WHERE id1 = column1 and id2 = ${column2}
Note that the ${replacement_variable} syntax only works in JavaScript when you define a string using backticks. It will not work when using single or double quotes to terminate a string.
Getting past those two may expose others, but could make it just run.
Related
I have the below records in my table,
If the HoleNumber combination is not having 'A' and 'B' for the particular datetime, we need to remove the alphabets from the number.
i.e., Remove 'A' from third record and sixth record. Because, it doesn't have B combinations for that datetime.
delete from myTable
where id in
(
select id from myTable t1
inner join
(
select [date], left([holeNumber], len(holeNumber)-1) as hNumber
from myTable
group by [date], left([holeNumber], len(holeNumber)-1)
having count(holeNumber) = 1
) tmp
on t1.[date] = tmp.[date] and left(t1.holeNumber, len(holeNumber)-1) = tmp.hNumber);
would do it, provided your requirements are strictly to remove having only 1 type of holeNumber.
DBFiddle demo
I have a column called empl_type_multi which is just a comma delimited column, each value is a link to another table called custom captions.
For instance, i might have the following as a value in empl_type_multi:
123, RHN, 458
Then in the custom_captions table these would be individual values:
123 = Dog
RHN = Cat
458 = Rabbit
All of these fields are NTEXT.
What i am trying to do is convert the empl_type_multi column and chance it to the respective names in the custom_captions table, so in the example above:
123, RHN, 458
Would become
Dog, Cat, Rabbit
Any help on this would be much appreciated.
----- EDIT ------------------------------------------------------------------
Ok so ive managed to convert the values to the corresponding caption and put it all into a temporary table, the following is the output from a CTE query on the table:
ID1 ID2 fName lName Caption_name Row_Number
10007 22841 fname1 lname1 DENTAL ASSISTANT 1
10007 22841 fname1 lname1 2
10007 22841 fname1 lname1 3
10008 23079 fname2 lname2 OPS WARD 1
10008 23079 fname2 lname2 DENTAL 2
10008 23079 fname2 lname2 3
How can i update this so that anything under caption name is added to the caption name of Row_Number 1 separated by a comma?
If i can do that all i need to do is delete all records where Row_Number != 1.
------ EDIT --------------------------------------------------
The solution to the first edit was:
WITH CTE AS
(
SELECT
p.ID1
, p.ID2
, p.fname
, p.lname
, p.caption_name--
, ROW_NUMBER() OVER (PARTITION BY p.id1ORDER BY caption_name DESC) AS RN
FROM tmp_cs p
)
UPDATE tblPerson SET empType = empType + ', ' + c.Data
FROM CTE c WHERE [DB1].dbo.tblPerson.personID = c.personID AND RN = 2
And then i just incremented RN = 2 until i got 0 rows affected.
This was after i ran:
DELETE FROM CTE WHERE RN != 1 AND Caption_name = ''
select ID1, ID2, fname, lname, left(captions, len(captions) - 1) as captions
from (
select distinct ID1, ID2, cast(fname as nvarchar) as fname, cast(lname as nvarchar) as lname, (
select cast(t1.caption_name as nvarchar) + ','
from #temp as t1
where t1.ID1 = t2.ID1
and t1.ID2 = t2.ID2
and cast(caption_name as nvarchar) != ''
order by t1.[row_number]
for xml path ('')) captions
from #temp as t2
) yay_concatenated_rows
This will give you what you want. You'll see casting from ntext to varchar. This is necessary for comparison because many logical ops can't be performed on ntext. It can be implicitly cast back the other way so no worries there. Note that when casting I did not specify length; this will default to 30, so adjust as varchar(length) as needed to avoid truncation. I also assumed that both ID1 and ID2 form a composite key (it appears this is so). Adjust the join as you need for the relationship.
you have just shared your part of problem,not exact problem.
try this,
DECLARE #T TABLE(ID1 VARCHAR(50),ID2 VARCHAR(50),fName VARCHAR(50),LName VARCHAR(50),Caption_name VARCHAR(50),Row_Number INT)
INSERT INTO #T VALUES
(10007,22841,'fname1','lname1','DENTAL ASSISTANT', 1)
,(10007,22841,'fname1','lname1', NULL, 2)
,(10007,22841,'fname1','lname1', NULL, 3)
,(10008,23079,'fname2','lname2','OPS WARD', 1)
,(10008,23079,'fname2','lname2','DENTAL', 2)
,(10008,23079,'fname2','lname2', NULL, 3)
SELECT *
,STUFF((SELECT ','+Caption_name
FROM #T T1 WHERE T.ID1=T1.ID1 FOR XML PATH('')
),1,1,'')
FROM #T T
You can construct the caption_name string easily by looping through while loop
declare #i int = 2,#Caption_name varchar(100)= (select series from
#temp where Row_Number= 1)
while #i <= (select count(*) from #temp)
begin
select #Caption_name = #Caption_name + Caption_name from #temp where Row_Number = #i)
set #i = #i+1
end
update #temp set Caption_name = #Caption_name where Row_Number = 1
and use case statement to remove null values
(select case when isnull(Caption_name ,'') = '' then
'' else ',' + Caption_name end
I want to update my attendance table on basis of the following condition.
NonWorking type is 1
If its previous day or next attendance type is Absent then I want to mark NonWorking type is LWP in DAOthers Column.
I think you can use LAG() and LEAD() here to peek at the preceding and proceeding values of the attendance type. Then, if one of those should be absent, mark the NonWorking column appropriately.
WITH cte AS (
SELECT *,
LAG(AttendanceType, 1, 'Present') OVER (ORDER BY ADate) AS lag_at,
LEAD(AttendanceType, 1, 'Present') OVER (ORDER BY ADate) AS lead_at
FROM yourTable
)
UPDATE cte
SET NonWorking = 1
WHERE lag_at = 'Absent' OR lead_at = 'Absent'
I am not sure whether you want an sql query to update existing data or a solution which is needed while making an entry.
Use below query to update existing data:
Update AttendanceTable set DaOthers =
(select top 1 'LWP' from AttendanceTable at1
where AttendanceTable.EmployeeId = at1.EmployeeId
and DATEADD(day, -1,AttendanceTable.ADate) = at1.ADate
and at1.NonWorking = 1)
Table befor executing above query:
Table after executing above query:
To update at the time of inserting record:
If you want to update while inserting data then you may need to set a variable first then use that variable while inserting. In the first query you need to use ADate and EmployeeID.The Nonworking is always 1.
DECLARE #DaOthers nvarchar(20) = (select top 1 'LWP' from AttendanceTable at
where DATEADD(day, 1, at.ADate) ='2017-02-04' and at.NonWorking = 1 and EmployeeId = 1)
insert into AttendanceTable
(NonWorking, ADate, AttendanceType, EmployeeId, DaOthers)
values
(0,'2017-02-04', 'Present', 1,#DaOthers)
With CTE as
(
SELECT *,
DATEADD(DAY, 1, Lag(ADate, 1,ADate)
OVER (PARTITION BY DAttendanceId ORDER BY ADate ASC)) AS EndDate
FROM tbl_DailyAttendance where EmployeeId = 1001 and AMonth = 2 and AYear = 2017 and AttendanceType = 'Absent' and NonWorking = 0
)
--select * from CTE
select * from tbl_DailyAttendance tda inner join CTE c on tda.ADate = c.EndDate where tda.EmployeeID = 1001 and tda.NonWorking = 1 order by tda.ADate
This is how i do for checking the conditions
since you hvn't provided sample data,so try to understand my query and correct if anything minor.
;WITH CTE as
(
select *
,isnull((select 1 from tbl_DailyAttendance tdb
where ((tdb.adate=DATEADD(day,-1,tda.adate))
or (tdb.adate=DATEADD(day,1,tda.adate)))
and attendancetype='Absent'
),0) NewnonWorkingType
from tbl_DailyAttendance tda
)
--Testing purpose
--select * from cte
update tda
set nonworking=b.NewnonWorkingType
,daOther=case when b.NewnonWorkingType=1 then 'LWP'
else null end
from tbl_DailyAttendance tda
inner join cte b on tda.id=b.id
I have a table like the following which is basically used to "give a name" to a value in a table (this table contains values for a bunch of other tables as well, not just for MYTABLE; I've omitted a few irrelevant fields from NAMEVALUEMAP):
NAMEVALUEMAP Table
---------------------
VALUE_ | NAME_
---------------------
0 | ZERO
1 | ONE
I didn't want to use JOINs so I thought of using Sub-Queries.
Problem is when a value does not exist in the NAMEVALUEMAP table then NULL is shown.
Instead of NULL I want to show the actual value from MYTABLE (MYTABLE has ID field as identity column and contains a few rows):
-- //Fine, prints word 'ZERO' when MYTABLE.ABC is 0
SELECT
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM
MYTABLE outer_
-- //Not Fine, prints NULL (because "999" is not in NAMEVALUEMAP). In this case, MYTABLE.ABC is 999
-- //Want it to print 999 if the value is not in NAMEVALUEMAP
SELECT
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID))
FROM
MYTABLE outer_
-- //Tried COALESCE, but the error is "Invalid column name 'VALUE_'"
SELECT
COALESCE((SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = (SELECT ABC FROM MYTABLE inner_ WHERE inner_.ID = outer_.ID)), ABC)
FROM
MYTABLE outer_
Also, is there a better way to do this sort of value-to-name mapping?
I would recomend using a LEFT JOIN (is there any reason you are voidung it?) and ISNULL
SELECT ISNULL(NAME_, ABC)
FROM MYTABLE m LEFT JOIN
NAMEVALUEMAP n ON m.ABC = n.VALUE_
Well, in that case you can try
SELECT ISNULL((select NAME_ FROM NAMEVALUEMAP WHERE VALUE_ = m.ABC), m.ABC)
FROM MYTABLE m
It is a left join, unless you want soem EXISTS/UNION construct. Not tested:
SELECT
COALESCE(N.VALUE, M.ABC)
FROM
MYTABLE M
LEFT JOIN
NAMEVALUEMAP N ON M.VALUE N.ABC
If you really want to avoid JOINs...
SELECT
ABC
FROM
MYTABLE M
WHERE
NOT EXISTS (SELECT * FROM NAMEVALUEMAP N WHERE M.VALUE N.ABC)
UNION ALL
SELECT
VALUE
FROM
NAMEVALUEMAP N
WHERE
EXISTS (SELECT * FROM MYTABLE M WHERE M.VALUE N.ABC)
Edit:
The SELECT *, 1 or NULL in EXISTS question again
Try EXISTS (SELECT 1/0...)
Mentioned in ANSI SQL 1992 Standard too, page 191
EDIT:
SELECT
COALESCE(
(SELECT NAME_ FROM NAMEVALUEMAP WHERE VALUE_ =
(SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID)
),
<int to string>(
SELECT ABC FROM MYINNERTABLE inner_ WHERE inner_.ID = outer_.ID
)
)
FROM
MYTABLE outer_
where column function <int to string> is appropriate for sqlserver. In mysql it would be CAST(). Without conversion, the query will throw a wobbly about the mismatched datatypes.
How to get Previous Column Value?
IIf id1 = id2 then display previous column id1 value
id1 id2
1001 1001
1002 1002
1003 1003
so on...
select id1, id2, Iff id2 = id1 then disply previous id1 value as idadjusted
Output
id1 id2 id3(Expected)
1001 1001 **1000**
1002 1002 **1001**
1003 1003 **1002**
so on...
I want to disply previous column value of id1
My query
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME,
CARDEVENTDATE AS LASTDATE, MAX(CARDEVENTTIME) AS LASTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME FROM (T_TITLE INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE) INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
For the LastDate - I want to Display Previous column cardeventdate value
For the Lasttime - I want to display previous column outtime value
Need Query Help?
The on clause is used to retrieve the previous id, I have tested it and works fine.
This solution will work even if intermediate ids are missiing i.e. ids are not consecutive
select t1.id, t1.column1, t1.column2,
case
when (t1.column1 = t1.column2) then t2.column1
else null
end as column3
from mytable t1
left outer join mytable t2
on t1.id = (select max(id) from mytable where id < t1.id)
For your complex query, you can create a view and then use the above sql format for your view:
Create a view MyView for:
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME
FROM T_TITLE
INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE
INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID
ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
And then the query would be:
select v1.CARDNO, v1.NAME, v1.TITLENAME, v1.CARDEVENTDATE, v1.INTIME, v1.OUTTIME,
case
when (v1.NAME = v1.TITLENAME) then v2.CARDEVENTDATE -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTDATE,
case
when (v1.NAME = v1.TITLENAME) then v2.OUTTIME -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTTIME
from myview v1
left outer join myview v2
on v2.CARDNO = (select max(CARDNO) from table1 where CARDNO < v1.CARDNO)
The v1.NAME = v1.TITLENAME in case stmt needs to be replaced with appropriate condn. I was not sure of the condn as its not mentioned in the question.
When you are designing your database you should consider the fact that you cannot rely on all the rows being in the right order. Instead you should create an identity value, that increment by one for every new row. And if you do this your solution becomes easy (or easier at least)
Assuming a new column called ID
SELECT colum1 FROM myTable WHERE ID = (SELECT ID FROM myTAble WHERE Column1 = Column2) - 1
If you get no match you will end up with ID -1 and this does not exist so you're ok.
If it is possible to get more than one match you will have to consider that too
Your table isn't in first normal form (1NF):
According to Date's definition of 1NF,
a table is in 1NF if and only if it is
'isomorphic to some relation', which
means, specifically, that it satisfies
the following five conditions:
1) There's no top-to-bottom ordering to the rows.
2) There's no left-to-right ordering to the columns.
3) ...