I'm still new to tsql and trying to figure out how to build this query.
I have two tables. One called mirror which has an official list of all campuses and is used to populate a drop down list of campuses for users on a webform. They then have 5 choices they can select, which then populates another table with their request when they submit the form(Request). ie. CampusChoice1, CampusChoice2..etc.
I am trying to build a page to display the end results of all the collected data. After some reading I'm thinking I might need to use PIVOT to make this happen but I can't get my head to see the query.
I can make a rudimentary query for each choice1-5, but I kind of wanted them all together will nulls or zeros where some campuses were not chosen.
Something like
--Simple count on single col
SELECT CampusChoice1, COUNT(*) as '#'
FROM Request
Group By CampusChoice1
Or
--But this doesn't give the results I want, since it does not account for all the POSSIBLE choices.
SELECT CampusChoice1, COUNT() as '#',
CampusChoice2, COUNT() as '#',
CampusChoice3, COUNT() as '#',
CampusChoice4, COUNT() as '#',
CampusChoice5, COUNT(*) as '#'
FROM Operations.dbo.TransferRequest
Group By CampusChoice1, CampusChoice2, CampusChoice3, CampusChoice4, CampusChoice5
Any ideas how I could show this? Am I on the right track at least with the PIVOT table?
Not sure if I understood your question correctly, but assuming that you have this:
CampusChoice | Other data ...
------------------------------
CampusChoice1 | ...
CampusChoice2 | ...
CampusChoice1 | ...
Then for the example above with only 3 rows you want this end result:
CampusChoice1 | 2 | CampusChoice2 | 1 | CampusChoice3 | 0 | ...
The T-SQL to achieve this is:
select
'CampusChoice1',
sum( case when CampusChoice = 'CampusChoice1' then 1 else 0 end ) '#',
'CampusChoice2',
sum( case when CampusChoice = 'CampusChoice2' then 1 else 0 end ) '#',
'CampusChoice3',
sum( case when CampusChoice = 'CampusChoice3' then 1 else 0 end ) '#',
...
from
...
Use the sum combined with the case to sum 1's for each row for CampusChoice1 and 0's for each row not CampusChoice1, repeating this for each CampusChoiceN.
Related
In Postgres if one of your columns is a big complicated expression you can just say ORDER BY 3 DESC where 3 is the order of the column where the complicated expression is. Is there anywhere to do this in SQLAlchemy?
As Gord Thompson observes in this comment, you can pass the column index as a text object to group_by or order_by:
q = sa.select(sa.func.count(), tbl.c.user_id).group_by(sa.text('2')).order_by(sa.text('2'))
serialises to
SELECT count(*) AS count_1, posts.user_id
FROM posts GROUP BY 2 ORDER BY 2
There are other techniques that don't require re-typing the expression.
You could use the selected_columns property:
q = sa.select(tbl.c.col1, tbl.c.col2, tbl.c.col3)
q = q.order_by(q.selected_columns[2]) # order by col3
You could also order by a label (but this will affect the names of result columns):
q = sa.select(tbl.c.col1, tbl.c.col2, tbl.c.col3.label('c').order_by('c')
Is it possible to add condition within the in clause of postgresql
for example
select ... where (t1.subject,t2.weight) in ((1,2),(2,3))
I want to check whether subject is 1 but weight can be >= 2 not just 2 and so on. So that condition would logically look somewhat like
select ... where (t1.subject,t2.weight) in ((1,>2),(2,>3))
No, this is not possible. You need to write
…
WHERE t1.subject = 1 AND t2.weight > 2
OR t1.subject = 2 AND t2.weight > 3;
You can select value of object using subquery. Simple just select query subject which are having weight greater than >=2.
select ... where (t1.subject,t2.weight) in (select subject FROM ... where weight >=2 ,select subject FROM ... where weight >=3 );
I need to use the split_part function on that query:
CREATE TABLE client_group_by_group_test AS SELECT *, SPLIT_PART( groupe,
',', 1 ) AS group1, SPLIT_PART(SPLIT_PART(groupe,',',2),',',-1) AS
group2, SPLIT_PART(SPLIT_PART(groupe,'',3),'',-3) AS group3,
SPLIT_PART(groupe,'',-4) AS group4 FROM planification_client
but it gives me the following error:
ERROR: field position must be greater than zero
So, how can I deal with negative values here?
Can this kind reverse(split_part(reverse(col_A), '_'::text, 1)) of statement work? I'm referencing to that question.
EDIT: I'm completely stuck with this query.
More details: I have one column with "server name" and another with its different groups separated with coma.
server name| group |
-----------+------------------------------+
XPTERTBIEP9|GRNW_SPO_S_F_H, GRNW_SPO_S_I_J|
The output I need to get is if the server has multiple groups, they need to be in the different column like group1, group2...
server name| group |group1 |group 2
-----------+------------------------------+--------------+--------------
XPTERTBIEP9|GRNW_SPO_S_F_H, GRNW_SPO_S_I_J|GRNW_SPO_S_F_H|GRNW_SPO_S_I_J
If the negative number is supposed to indicated the offset from the end, a two step approach might be better:
CREATE TABLE client_group_by_group_test
AS
SELECT ...,
agroups[1] as group1,
agroups2[cardinality(agroups2) - 1] as groups2,
agroups3[cardinality(agroups3) - 3] as groups3,
agroups[cardinality(agroups) - 4] as group4
from (
select *,
string_to_array(groupe, ',') as agroups,
(string_to_array(string_to_array(groupe, ','), ',')[2]) as agroups2,
(string_to_array(string_to_array(groupe, ','), ',')[3]) as agroups3,
from planification_client
) t
Note that you need to list the desired columns in the outer most SELECT to exclude the intermediate "agroups" columns.
In the table below I am storing some conditions like this:
Then, generally, in second table, I am having the following records:
and what I need is to compare these values using the right condition and store the result ( let's say '0' for false, and '1' for true in additional column).
I am going to do this in a store procedure and basically I am going to compare from several to hundreds of records.
What of the possible solution is to use sp_executesql for each row building dynamic statements and the other is to create my own scalar function and to call it for eacy row using cross apply.
Could anyone tell which is the more efficient way?
Note: I know that the best way to answer this is to make the two solutions and test, but I am hoping that there might be answered of this, based on other stuff like caching and SQL internal optimizations and others, which will save me a lot of time because this is only part of a bigger problem.
I don't see the need in use of sp_executesql in this case. You can obtain result for all records at once in a single statement:
select Result = case
when ct.Abbreviation='=' and t.ValueOne=t.ValueTwo then 1
when ct.Abbreviation='>' and t.ValueOne>t.ValueTwo then 1
when ct.Abbreviation='>=' and t.ValueOne>=t.ValueTwo then 1
when ct.Abbreviation='<=' and t.ValueOne<=t.ValueTwo then 1
when ct.Abbreviation='<>' and t.ValueOne<>t.ValueTwo then 1
when ct.Abbreviation='<' and t.ValueOne<t.ValueTwo then 1
else 0 end
from YourTable t
join ConditionType ct on ct.ID = t.ConditionTypeID
and update additional column with something like:
;with cte as (
select t.AdditionalColumn, Result = case
when ct.Abbreviation='=' and t.ValueOne=t.ValueTwo then 1
when ct.Abbreviation='>' and t.ValueOne>t.ValueTwo then 1
when ct.Abbreviation='>=' and t.ValueOne>=t.ValueTwo then 1
when ct.Abbreviation='<=' and t.ValueOne<=t.ValueTwo then 1
when ct.Abbreviation='<>' and t.ValueOne<>t.ValueTwo then 1
when ct.Abbreviation='<' and t.ValueOne<t.ValueTwo then 1
else 0 end
from YourTable t
join ConditionType ct on ct.ID = t.ConditionTypeID
)
update cte
set AdditionalColumn = Result
If above logic is supposed to be applied in many places, not just over one table, then yes you may think about function. Though I would used rather inline table-valued function (not scalar), because of there is overhead imposed with use of user defined scalar functions (to call and return, and the more rows to be processed the more time wastes).
create function ftComparison
(
#v1 float,
#v2 float,
#cType int
)
returns table
as return
select
Result = case
when ct.Abbreviation='=' and #v1=#v2 then 1
when ct.Abbreviation='>' and #v1>#v2 then 1
when ct.Abbreviation='>=' and #v1>=#v2 then 1
when ct.Abbreviation='<=' and #v1<=#v2 then 1
when ct.Abbreviation='<>' and #v1<>#v2 then 1
when ct.Abbreviation='<' and #v1<#v2 then 1
else 0
end
from ConditionType ct
where ct.ID = #cType
which can be applied then as:
select f.Result
from YourTable t
cross apply ftComparison(ValueOne, ValueTwo, t.ConditionTypeID) f
or
select f.Result
from YourAnotherTable t
cross apply ftComparison(SomeValueColumn, SomeOtherValueColumn, #someConditionType) f
I have not worked much with TSQL or the full-text search feature of SQL Server so bear with me.
I have a table nvarchar column (Col) like this:
Col ... more columns
Row 1: '1'
Row 2: '1|2'
Row 3: '2|40'
I want to do a search to match similar users. So if I have a user that has a Col value of '1' I would expect the search to return the first two rows. If I had a user with a Col value of '1|2' I would expect to get Row 2 returned first and then Row 1. If I try to match users with a Col value of '4' I wouldn't get any results. I thought of doing a 'contains' by splitting the value I am using to query but it wouldn't work since '2|40' contains 4...
I looked up the documentation on using the 'FREETEXT' keyword but I don't think that would work for me since I essentially need to break up the Col values into words using the '|' as a break.
Thanks,
John
You should not store values like '1|2' in a field to store 2 values. If you have a maximum of 2 values, you should use 2 fields to store them. If you can have 0-many values, you should store them in a new table with a foreign key pointing to the primary key of your table..
If you only have max 2 values in your table. You can find your data like this:
DECLARE #s VARCHAR(3) = '1'
SELECT *
FROM <table>
WHERE #s IN(
PARSENAME(REPLACE(col, '|', '.'), 1),
PARSENAME(REPLACE(col, '|', '.'), 2)
--,PARSENAME(REPLACE(col, '|', '.'), 3) -- if col can contain 3
--,PARSENAME(REPLACE(col, '|', '.'), 4) -- or 4 values this can be used
)
Parsename can handle max 4 values. If 'col' can contain more than 4 values use this
DECLARE #s VARCHAR(3) = '1'
SELECT *
FROM <table>
WHERE '|' + col + '|' like '%|' + #s + '|%'
Need to mix this in with a case for when there is no | but this returns the left and right hand sides
select left('2|10', CHARINDEX('|', '2|10') - 1)
select right('2|10', CHARINDEX('|', '2|10'))