I am on a work term from school. I am not very comfortable using SQL, I am trying to get a hold of it....
My supervisor gave me a task for a user in which I need to take row data and make columns. We used the Crosstab Wizard and automagically created the SQL to get what we needed.
Basically, we have a table like this:
ReqNumber Year FilledFlag(is a checkbox) FilledBy
1 2012 (notchecked) ITSchoolBoy
1 2012 (checked) GradStudent
1 2012 (notchecked) HighSchooler
2 etc, etc.
What the user would like is to have a listing of all of the req numbers and what is checked
Our automatic pivot code gives us all of the FilledBy options (there are 9 in total) as column headings, and groups it all by reqnumber.
How can you do this without the pivot? I would like to wrap my head around this. Nearest I can find is something like:
SELECT
SUM(IIF(FilledBy = 'ITSchoolboy',1,0) as ITSchoolboy,
SUM(IIF(FilledBy = 'GradStudent',1,0) as GradStudent, etc.
FROM myTable
Could anyone help explain this to me? Point me in the direction of a guide? I've been searching for the better part of a day now, and even though I am a student, I don't think this will be smiled upon for too long. But I would really like to know!
I think your boss' suggestion could work if you GROUP BY ReqNumber.
SELECT
ReqNumber,
SUM(IIF(FilledBy = 'ITSchoolboy',1,0) as ITSchoolboy,
SUM(IIF(FilledBy = 'GradStudent',1,0) as GradStudent,
etc.
FROM myTable
GROUP BY ReqNumber;
A different approach would be to JOIN multiple subqueries. This example pulls in 2 of your categories. If you need to extend it to 9 categories, you would have a whole lot of joining going on.
SELECT
itsb.ReqNumber,
itsb.ITSchoolboy,
grad.GradStudent
FROM
(
SELECT
ReqNumber,
FilledFlag AS ITSchoolboy
FROM myTable
WHERE FilledBy = "ITSchoolboy"
) AS itsb
INNER JOIN
(
SELECT
ReqNumber,
FilledFlag AS GradStudent
FROM myTable
WHERE FilledBy = "GradStudent"
) AS grad
ON itsb.ReqNumber = grad.ReqNumber
Please notice I'm not suggesting you should use this approach. However, since you asked about alternatives to your pivot approach (which works) ... this is one. Stay tuned in case someone else offers a simpler alternative. :-)
Related
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!
is there any way within snowflake/sql query to view what tables are being queried the most as well as what columns? I want to know what data is of most value to my users and not sure how to do this programatically. Any thoughts are appreciated - thank you!
2021 update
The new ACCESS_HISTORY view has this information (in preview right now, enterprise edition).
For example, if you want to find the most used columns:
select obj.value:objectName::string objName
, col.value:columnName::string colName
, count(*) uses
, min(query_start_time) since
, max(query_start_time) until
from snowflake.account_usage.access_history
, table(flatten(direct_objects_accessed)) obj
, table(flatten(obj.value:columns)) col
group by 1, 2
order by uses desc
Ref: https://docs.snowflake.com/en/sql-reference/account-usage/access_history.html
2020 answer
The best I found (for now):
For any given query, you can find what tables are scanned through looking at the plan generated for it:
SELECT *, "objects"
FROM TABLE(EXPLAIN_JSON(SYSTEM$EXPLAIN_PLAN_JSON('SELECT * FROM a.b.any_table_or_view')))
WHERE "operation"='TableScan'
You can find all of your previous ran queries too:
select QUERY_TEXT
from table(information_schema.query_history())
So the natural next step would be combine both - but that's not straightforward, as you'll get an error like:
SQL compilation error: argument 1 to function EXPLAIN_JSON needs to be constant, found 'SYSTEM$EXPLAIN_PLAN_JSON('SELECT * FROM a.b.c')'
The solution would be to combine the queries from the query_history() with the SYSTEM$EXPLAIN_PLAN_JSON outside (to make the strings constant), and then you will be able to find out the most queried tables.
Using Microsoft Access, I normally use condition (mostly where) to obtain the data I want to display.
So far, it went well. However now I have a complex filtering and I'm not sure of the best way to do it. I will explain how I do it with many queries, and I'd like to know if there is something simpler, since I feel like it's doing too much for what I accomplish.
I have Building and Energy tables. Between them, I have a link table since a Building has a list of possible energies.
My goal is to display ALL energy not already associated with the building.
I first have a simple query to display all the IDs of energy that are in the link table where building is the one of interest.
Once I do that, I have another query using this one, which display an energy if it is an energy absent from previous list.
This takes 2 queries and I feel like I could have a better way to do this. I'm fairly new to MS Access, so any suggestion is welcome.
Here is the first request to obtain the list of energies:
SELECT
Batiments.ID, Energies.ID, Energies.Type
FROM
Energies
INNER JOIN
(Batiments
INNER JOIN
Batiment_Energie ON Batiments.ID = Batiment_Energie.Batiment_ID) ON Energies.ID = Batiment_Energie.Energie_ID
WHERE
(((Batiments.ID) = " & cbxBatiments.Column(0) & "));"
You can query the non-associated energy types with
SELECT
ID, Type
FROM
Energies
WHERE
ID NOT IN (SELECT Energie_ID
FROM Batiment_Energie
WHERE Batiment_ID = 123)
where 123 is to be replaced by the Id comming from cbxBatiments.Column(0).
You can use not exists:
select e.*
from energie as e
where not exists (select 1
from Batiment_Energie as be
where be.energie_id = e.id and be.batiment_id = <your id>
);
I have four tables now.
StuInfo
ActInfo
ActAttendance
ActLateArriveAndEarlyLeave
For Type, 1 = late arrive, 2 = early leave
Is it possible to generate a query like this with one sql statement?
C3:E4 are the cells which store the total time a person invloved in an activity.
Or if it is not possible, I want to export the final result to an Excel file.
How can I do it in VBA?
Thanks very much. Please let me know if I didn't explain clearly enough.
Pivot table is what you need unfortunately I cannot find a way to export one from Access as a flat query. It will only export it as a pivot table in excel. This query will get you the correct data. Then you have to create a pivot from it
SELECT DISTINCT
StuInfo.StuName AS Name,
StuInfo.Stu_No,
DateDiff("h",IIf([AcctLateAriveAndEarlyLeave].[Type]=1,[AcctLateAriveAndEarlyLeave].[Time],[AcctInfo].[sTime]),IIf([AcctLateAriveAndEarlyLeave].[Type]=2,[AcctLateAriveAndEarlyLeave].[Time],[AcctInfo].[eTime])) AS AttendedFor, Format([AcctInfo].[sTime],"mm/dd/yyyy") AS OnDate
FROM ((StuInfo LEFT JOIN AcctAttendance ON StuInfo.Stu_No = AcctAttendance.Stu_No) LEFT JOIN AcctInfo ON AcctAttendance.[Act_S/N] = AcctInfo.[S/N]) LEFT JOIN AcctLateAriveAndEarlyLeave ON StuInfo.Stu_No = AcctLateAriveAndEarlyLeave.Stu_No;
Then you can create a pivot table that looks like this
Obviously if you want something other than explicit hours you have to change the query a bit.
A crosstab query can work. However, I need a little bit more information for what the values under date fields calculate. In my example I assume they are Max(Type)
TRANSFORM Max(Type) AS MaxOfType
SELECT StuInfo.SteName, StuInfo.Stu_No FROM StuInfo
INNER JOIN ActLateArriveAndEarlyLeave ON StuInfo.Stu_No = ActLateArriveAndEarlyLeave.Stu_No
GROUP BY StuInfo.Ste_No, StuInfo.SteName
PIVOT Format(ActLateArriveAndEarlyLeave.TimeValue, 'short date');
I am new to sql server, transitioning from mysql.
I have a complicated case statement that I would like to group on 6 whens and an else. Likely to get larger. To be able to run it, I need to copy the statement into the group by each time there is a modification. In mySql I would just group by the column number. Is there any work around for this? Making the code very ugly.
Is there going to be a performance penalty in creating a sub query for my case, then just grouping on the result field. Seems like trying to make the code more elegant will cause the query to use more resources.
Thanks
Below is a field I am grouping on. As I make a modification to the field for more edge cases, then I need to change code in up to 3 places. Makes for some very ugly code, and I need no extra help doing that myself.
dz_code = case
when isnull(dz.dz_code,'N/A') in ('GAB', 'MAB', 'N/A') and dc.howdidyouhear = 'Television' then 'Television'
when isnull(dz.dz_code,'N/A') in ('GAB', 'MAB', 'N/A') and dc.howdidyouhear in ('Other', 'N/A') then 'Other'
WHEN dz.dz_code = 'irs,irs' THEN 'irs'
when dz.dz_code like '%SDE%' THEN 'SDE'
when dz.dz_code like 'referral,' then REPLACE(dz.dz_code, 'referral','')
when charindex(',',dz.dz_code) = 4 then left(dz.dz_code,3)
else
dz.dz_code
END,
Maybe you can wrap the query in a subquery and use the alias in the select and the group by. It looks a little bulky in this example, but if you've got more complex case switches, or more than one of them, then this solution will probably much smaller and more readable.
select
CaseField
from
(select
case when 1 = 2 then
3
else 4 end as CaseField
from
YourTable t) c
group by
CaseField