VFP sql prepass - sql

I have no idea what the official name for it is so maybe that's why i can't find anything online.
Basically, when you use sql in vfp it does an initial pass through (sometimes 2?) without moving the record cursor or saving the results.
Unfortunately I have sub routines in my sql that run and change things during that initial pass.
Why am i using subroutines in sql queries? Because vfp doesn't support referencing outside a subquery within the select items (once again i don't know the official name).
Example: select id, (select detail.name from detail where master.id == detail.id) name from master
This does work though: select id, getname(id) from master
where getname() is a sub routine containing the sql from the first example.
You could also use a join, but the above is just an example and a join does not work in my case.
Is there any way to deal with initial pass throughs? Does vfp create a boolean like firstpass or something? I suppose i could add a count to my subroutine, but that seems messier than it already is.
Alternatively can someone explain or link me an explanation to vfp's initial pass? I believe it was only doing one initial pass before but now it's doing two after changing some code.
Edit: ok, i was wrong. The above example does work. What doesn't work is the following:
SELECT d2.id, (SELECT TOP 1 d1.lname l FROM dpadd d1 WHERE d1.id== d2.id ORDER BY l) FROM dpadd d2
It gives me a "SQL: Queries of this type are not supported" error.
Strangely it works if i do the following:
SELECT d2.id, (SELECT COUNT(d1.lname) FROM dpadd d1 WHERE d1.id == d2.id) FROM dpadd d2
About the subroutines, they are methods of my form. The databases are local .dbf files. I'm not interacting with any servers, just running straight sql commands with into cursor clauses and then generating reports (usually).
I'll post back in a few minutes with an actually useful select statement that "is not supported". I'm sure you've noticed the top 1 example is completely useless.

It appears that TOP is not permitted in projections. For that example, you can instead do this:
SELECT d2.id, (SELECT MAX(d1.lname) l FROM dpadd d1 WHERE d1.id== d2.id) FROM dpadd d2
What else is giving you a problem?
Tamar

Related

Access DB engine does not recognize field when using Crosstab and subquery joins

I am in MS Access trying to join two queries. The first query is a Crosstab query:
TRANSFORM Sum(Q1.Downtime) AS SumOfDowntime
SELECT Q1.Batch
FROM [QryDowntime] Q1
GROUP BY Q1.Batch
PIVOT Q1.Category;
This runs, no issues. It is summing downtime for OEE for context. Output looks something like:
Batch Availability Performance Quality
1 0 5 2
2 3 1 5
...
I then have a separate query that pulls the date from the previous record:
SELECT B2.Batch,
(SELECT TOP 1 B1.LastPallet
FROM TblBatches AS B1
WHERE B1.ID < B2.ID
ORDER BY B1.ID DESC) AS PrevEnd
FROM TblBatches AS B2;
Again, no issues. This runs and the output looks something like:
Batch PrevEnd
1 8/2/2021
2 8/5/2021
...
I have a summary table and want to join these two.
SELECT B1.Batch,
Q1.Availability,
Q1.Performance,
Q1.Quality,
Q2.PrevEnd
FROM (TblBatches AS B1
LEFT JOIN QryCrosstab AS Q1 ON B1.Batch = Q1.Batch)
LEFT JOIN QryDate AS Q2 ON B1.Batch = Q2.Batch;
I thought this would be the easy part but I get the error "The Microsoft Access database engine does not recognize 'B2.ID' as a valid field name or expression." If I remove either of the joins, the query works fine.
I am aware of this solution but, as the author states, it is not really a solution. I do not want to use more tables if there is another way to fix the error.
I tried this solution but it is not quite the same. I don't really have a subquery I can do beforehand. If I can, I do not know how to do it. There is nothing dynamic. I am not accepting user inputs. These are straightforward queries. I am hoping there is a strange typo or incorrect syntax.
Any ideas would be greatly appreciated!

SQL Query for Search Page

I am working on a small project for an online databases course and i was wondering if you could help me out with a problem I am having.
I have a web page that is searching a movie database and retrieving specific columns using a movie initial input field, a number input field, and a code field. These will all be converted to strings and used as user input for the query.
Below is what i tried before:
select A.CD, A.INIT, A.NBR, A.STN, A.ST, A.CRET_ID, A.CMNT, A.DT
from MOVIE_ONE A
where A.INIT = :init
AND A.CD = :cd
AND A.NBR = :num
The way the page must search is in three different cases:
(initial and number)
(code)
(initial and number and code)
The cases have to be independent so if certain field are empty, but fulfill a certain case, the search goes through. It also must be in one query. I am stuck on how to implement the cases.
The parameters in the query are taken from the Java parameters in the method found in an SQLJ file.
If you could possibly provide some aid on how i can go about this problem, I'd greatly appreciate it!
Consider wrapping the equality expressions in NVL (synonymous to COALESCE) so if parameter inputs are blank, corresponding column is checked against itself. Also, be sure to kick the a-b-c table aliasing habit.
SELECT m.CD, m.INIT, m.NBR, m.STN, m.ST, m.CRET_ID, m.CMNT, m.DT
FROM MOVIE_ONE m
WHERE m.INIT = NVL(:init, m.INIT)
AND m.CD = NVL(:cd, m.CD)
AND m.NBR = COALESCE(:num, m.NBR)
To demonstrate, consider below DB2 fiddles where each case can be checked by adjusting value CTE parameters all running on same exact data.
Case 1
WITH
i(init) AS (VALUES('db2')),
c(cd) AS (VALUES(NULL)),
n(num) AS (VALUES(53)),
cte AS
...
Case 2
WITH
i(init) AS (VALUES(NULL)),
c(cd) AS (VALUES(2018)),
n(num) AS (VALUES(NULL)),
cte AS
...
Case 3
WITH
i(init) AS (VALUES('db2')),
c(cd) AS (VALUES(2018)),
n(num) AS (VALUES(53)),
cte AS
...
However, do be aware the fiddle runs a different SQL due to nature of data (i.e., double and dates). But query does reflect same concept with NVL matching expressions on both sides.
SELECT *
FROM cte, i, c, n
WHERE cte.mytype = NVL(i.init, cte.mytype)
AND YEAR(CAST(cte.mydate AS date)) = NVL(c.cd, YEAR(CAST(cte.mydate AS date)))
AND ROUND(cte.mynum, 0) = NVL(n.num, ROUND(cte.mynum, 0));

How to query only old and duplicate data from a database in SQL

I'm trying to query my database to pull only duplicate/old data to write to a scratch section in excel (Using a macro passing SQL to the DB).
For now, I'm currently testing in Access alone to only filter out the old data.
First, I'm trying to filter my database by a specifed WorkOrder, RunNumber, and Row.
The code below only filters by Work Order, RunNumber, and Row. ...but SQL doesn't like when I tack on a 2nd AND statement; so this currently isn't working.
SELECT *
FROM DataPoints
WHERE (((DataPoints.[WorkOrder])=[WO2]) AND ((DataPoints.[RunNumber])=6) AND ((DataPoints.[Row]=1)
Once I figure that portion out....
Then if there is only 1 entry with specified WorkOrder, RunNumber, and Row, then I want filter it out. (its not needed in the scratch section, because its data is already written to the main section of my report)
If there are 2 or more entries with said criteria(WO, RN, and Row), then I want to filter out the newest entry based on RunDate and RunTime, and only keep all older entries.
For instance, in the clip below. The only item remaining in my filtered query will be the top entry with the timestamp 11:47:00AM.
.
Are there any recommended commands to complete this problem? Any ideas are helpful. Thank you.
I would suggest something along the lines of the following:
select t.*
from datapoints t
where
t.workorder = [WO2] and
t.runnumber = 6 and
t.row = 1 and
exists
(
select 1
from datapoints u
where
u.workorder = t.workorder and
u.runnumber = t.runnumber and
u.row = t.row and
(u.rundate > t.rundate or (u.rundate = t.rundate and u.runtime > t.runtime))
)
Here, if the correlated subquery within the where clause finds a record with the same workorder, runnumber and row, but with either a later rundate or the same rundate and a later runtime, then the record is returned by the main query.
You need two more )'s at the end of your code snippet. Or you can delete the parentheses completely in this example, MS Access will ad them back in as it deems necessary.
M.S. Access SQL can be tricky as it is not standards compliant and either doesn't allow for super complex queries, or it needs an ugly work around, like having a parentheses nesting nightmare when trying to join more than two tables.
For these reasons, I suggest using multiple Access queries to produce your results.

BigQuery load config variables from a table

I have a table defining constants in a single row. I want to construct a query on another table by using the value of these constants, something like:
SELECT DataTable.name FROM DataTable WHERE DataTable.key >
Config.keyConstant
but I have no idea how I can do this cleanly. In this case it could be done by using a CROSS JOIN
SELECT DataTable.name FROM (DataTable CROSS JOIN Config) WHERE DataTable.key >
Config.keyConstant
But this gets really messy as my queries get larger and the config is needed in different places.
Any suggestions? In SQL I'd think you'd do this with variables.
EDIT: Actually I want to be able to do something like
SELECT IF(Config.keyConstant*DataTable.key=1, DataTable.name, "John") FROM DataTable
This means that unfortunately I can't move all of the conditional logic into a WHERE EXISTS clause like suggested in an answer (although I wasn't aware of this, and it is cool).
I think you are in the right direction:
Something like below should work for both BigQuery Legacy and Standard SQL and having that Config has just one row makes CROSS JOIN not that bad looking.
SELECT DataTable.name
FROM DataTable
CROSS JOIN Config
WHERE DataTable.key1 > Config.key1Constant
AND DataTable.key2 = Config.key2Constant
AND DataTable.key3 < Config.key3Constant
In BigQuery Standard SQL you can change this to below, which somehow looks to me a little bit more portable:
SELECT
DataTable.name
FROM DataTable
WHERE EXISTS (
SELECT 1 FROM config
WHERE DataTable.key1 > key1Constant
AND DataTable.key2 = key2Constant
AND DataTable.key3 < key3Constant
)
Few notes:
cost wise - even though Config table is small - each time it will be contributing extra 10MB to the billing bytes
having extra column(s) in Config (like id ) will allow you to manage different versions of constants to be used by calling specific id value. Or condition based logic can be used to invoke needed constants
This is to answer updated question:
SELECT
CASE WHEN Config.keyConstant*DataTable.key=1
THEN DataTable.name ELSE "John"
END as name
FROM DataTable
CROSS JOIN Config

Select statement does not pull all the data from a field - SQL Server 2008 R2

I have this query to get results out of my database. My problem is that the selectedanswer part of the select statement does not pull all of the data from r.textboxmulti.
Below is my query.
<cfquery name="fullResults" datasource="#variables.dsn#">
select s.id, s.name surveyname, q.question, subq.answer subquestion, isnull(isnull(isnull(isnull(a.answer, **r.textboxmulti**),r.other),r.textbox),r.truefalse) as **selectedanswer**, a.*, r.*
from results r
join questions q on r.questionidfk = q.id
left join answers subq on r.itemidfk = subq.id
left join answers a on r.answeridfk = a.id
join surveys s on q.surveyidfk = s.id
where owneridfk = <cfqueryparam value="#arguments.ownerid#" cfsqltype="CF_SQL_VARCHAR" maxlength="35">
order by s.id, owneridfk, q.rank, subq.rank desc
</cfquery
Try using COALESCE instead of ISNULL. These lead to different data type precedence rules - I suspect a.answer is varchar(255). Also can't hurt to explicitly convert the first argument:
COALESCE(CONVERT(VARCHAR(MAX), a.answer),
r.textboxmulti, r.other, r.textbox, r.truefalse)
Could you explain what you mean by "all the data"? If you mean that it is not pulling data from r.textboxmulti for some rows, that mean that it is null for those rows and that fact is being masked by by the isnulls you have it wrapped in (incidentally, you could consider using a coalesce instead of nesting isnull....)
If you mean that it is getting data but leaving some of it off then one possibility is that it is being truncated. This can happen if SQL Server (or the next stage of processing where you are veiwing it...) sees it as a data type that is too small to hold the return value, this can sometimes happen due to implicit type conversions. You can deal with that by explicitly casting towards a large enough data type.
A final, rare, possibility is that r.textboxmulti containst an ascii null character. Many programs (including the SQL Server print command...) take that as a command to stop displaying anything from that string afterwards. This does not come up often, but I have encountered it myself.
In SQL Server management studio there is a setting that tells it how many characters to show for a column in the grid, or in text view.
If you're going to use the data in an application; are you seing all the data there? That is a sure sign that you use the default setting in SSMS to show only 255 characters.