Related
I have a table of soccer match data, among many other columns I have columns containing the team Ids for the home team and the away team.
Often times I want to find all matches between two teams I need to construct a query that looks like
(`home_id` = X AND `away_id` = Y) OR (`home_id` = Y AND `away_id` = X)
This works fine, but ideally I could shorten this query and remove the OR and second and clause.
Is this something mySQL can handle, and is there a limit to the number of columns this can apply to?
You could use tuples:
where ('X', 'Y') in ( (home_id, away_id), (away_id, home_id) )
or:
where (home_id, away_id) in ( ('X', 'Y'), ('Y', 'X') )
I'd like to know if it's possible to pass rows of data directly into a select subquery, rather than setting up a temporary table and joining on that.
My actual use case is trying to prevent thousands of individual queries, and for architectural reasons adding a temporary table would be a pain (but not impossible, so it's where I may have to go.)
An simplified example of my issue is :
I have a table giving the number plate of the cars in a car park, with each row containing section (a letter), space (a number), and reg_plate (a tinytext).
My boss gives me a list of 3 places and wants the reg number of the car in each (or null if empty).
Now I can do this by creating a temporary table containing the section/space sequence I'm interested in, and then join my carpark table against that to give me each of the rows.
I'm wondering is there a syntax where I could do this in a select, perhaps with a subselect something like this - obviously invalid, but hopefully it shows what I'm getting at:
SELECT targets.section, targets.space, cp.reg_plate
FROM carpark cp
LEFT JOIN (
SELECT field1 AS section, field2 AS space
FROM (
('a', 7), ('c', 14), ('c', 23)
)
) targets ON (cp.section = targets.section AND cp.space = targets.space)
Any ideas gratefully received!
You can use UNION:
SELECT targets.section, targets.space, cp.reg_plate
FROM carpark cp
LEFT JOIN (
SELECT 'a' as section, 7 AS space
UNION ALL
SELECT 'c', 14
UNION ALL
SELECT 'c', 23
) targets ON cp.section = targets.section AND cp.space = targets.space
A followup;
I realised I was hoping to find something analagous to the VALUES used in an insert statement.
It turns out this is available in MySQL 8+, and VALUES is available as a table constructor:
https://dev.mysql.com/doc/refman/8.0/en/values.html
SELECT targets.section, targets.space, cp.reg_plate
FROM carpark cp
LEFT JOIN (
VALUES
ROW ('a', 7), ROW('c', 14), ROW('c', 23)
)
) targets ON (cp.section = targets.column_0 AND cp.space = targets.column_1)
Not available in earlier MySQL (so the UNION method is OK) but great in 8+.
I am trying to select multiple rows based on 3 columns matching particular criteria. For a single search I do the following:
SELECT user_id
FROM users_to_users
WHERE user_id = '1' AND contact_user_id = '9' AND contact_blocked = 1
I would like to submit a set of values to return multiple rows.
so my values would be as such:
('1', '9', 1), ('2, '9', 1),('3', '9', 1) etc...
And return user_id's for the rows which match. In essence I'm trying to see which users have blocked user '9' so that I could then add only the users that are not blocked to the next statement.
Being very unfamiliar with SQL what I thought might work was the following:
SELECT user_id
FROM users_to_users
WHERE (user_id, contact_user_id, contact_blocked) VALUES (...)
But unable to do that. Is there any way to select multiple rows based on matching conditions for multiple columns?
Are you trying to use tuples with in? If so, this works:
SELECT user_id
FROM users_to_users
WHERE (user_id, contact_user_id, contact_blocked) in ( (1, 9, 1), (2, 9, 1), (3, 9, 1) )
There may be other ways, however, to accomplish your ultimate goal.
Thank you for coming to look at my question.
I have an SQL group by function which I'd like to add parameters to. (If that's possible)
I've tried to splice the parameters, two columns from the table into the function but I don't seem to get it right.
This function creates a table that counts records, I would like to be able to filter with parameters by 'Team' and 'Location'.
How would I go about adding this information to the dataset to allow me to filter?
I would normally add them using:
select
i.Team
,i.Location
From
incident i
Where i.Team in (#Team)
and i.Location in (#Location)
The table is called incident and all the information is from the same table.
I would very much appreciate an idea to do this. Thank you.
Oh, and I'm using Report Builder 3, with SQL 2008 R2
declare #st_date datetime;
declare #en_date datetime;
declare #days int;
declare #offset int;
set #en_date = (#en_datein);
set #offset = (#BrowserTimezoneOffset);
set #days = -6;
set #st_date = DATEADD(dd, #days, #en_date);
with daterange(dt) as
(select
#st_date dt
union all
select
DATEADD(dd, 1, dt) dt
from daterange
where dt <= DATEADD(dd, -1, #en_date)
)
select
left(DATENAME(dw, dt), 3) as weekday
,ISNULL(sum(inc.createdc), 0) as createdcount
,ISNULL(sum(inr.resolvedclosedc), 0) as resolvedclosedcount
from daterange left outer join
(select
left(DATENAME(dw,DATEADD(mi,#offset,CreatedDateTime)), 3) as createddatetime
,count(recid) as createdc
from Incident
where DATEADD(mi,#offset,CreatedDateTime) >= #st_date
and DATEADD(mi,#offset,CreatedDateTime) <= #en_date
group by left(DATENAME(dw, DATEADD(mi,#offset,CreatedDateTime)), 3)
) as inc
on inc.CreatedDateTime = left(DATENAME(dw, dt), 3)
left outer join
(select
left(DATENAME(dw, DATEADD(mi,#offset,ResolvedDateTime)), 3) as ResolvedDateTime
,count(case when status in ('Resolved', 'Closed') then 1 end) as resolvedclosedc
from Incident
where DATEADD(mi,#offset,ResolvedDateTime) between #st_date and #en_date
group by left(DATENAME(dw, DATEADD(mi,#offset,ResolvedDateTime)), 3)
) as inr
on inr.ResolvedDateTime = left(DATENAME(dw, dt), 3)
group by dt
order by dt
When using parameters that will be using one or many values you may tie them to a dataset as well.
Say if I have orders and people in a pretend sequence but I want to find orders of only certain people. I would follow a few steps:
I would create a dataset only for a parameter and call it 'People' for this example lets use a table variable that self executes and place this 'Query' box for a dataset.
declare #People Table ( personID int identity, person varchar(8));
insert into #People values ('Brett'),('Sean'),('Chad'),('Michael')
,('Ray'),('Erik'),('Queyn');
select * From #People
I would want to start with the dependency first which is a variable #Person I set up as an Integer and check 'Allow multiple values'. I then choose 'Available Values' on the left pane of the variable. I choose 'Get values from a query' choose my 'people' dataset from 1, choose PersonID as the Value field, and person as the label.
Now my parameter is bound and I can move on to my orders set. Again create a Dataset but call this one 'OrdersMain' and use a self extracting table variable but I am adding a predicate now referencing my variable from above as well.
declare #Orders table ( OrderID int identity, PersonID int, Desciption varchar(32), Amount int);
insert into #Orders values (1, 'Shirt', 20),(1, 'Shoes', 50),(2, 'Shirt', 22),
(2, 'Shoes', 52),(3, 'Shirt', 20),(3, 'Shoes', 50),(3, 'Hat', 20),
(4, 'Shirt', 20),(5, 'Shirt', 20),(5, 'Pants', 30), (6, 'Shirt', 20),
(6, 'RunningShoes', 70),(7, 'Shirt', 22),(7, 'Shoes', 40),(7, 'Coat', 80)
Select * from #Orders where PersonID in (#Person)
Now if populate my report with a tablix item and put the values from 'OrdersMain' in a tablix a user is prompted with a label for Brett, Sean, etc.. but the id is used for the orders to limit the scope of the dataset.
Optional
You can repeat step 1 for a SUBSET of people in another dataset and call it 'Defaults'. Then with an expanse of step 2 leave everything as is, but add this new dataset to 'Default Values' get from a query. This way I could create a temp table to get some of my people I most often use and then set them to be defaults instead. This would make the report auto execute when called.
Filtering can mean other things in SSRS as well. You can on any dataset see on the left pane a 'filter' and you may apply this. Keep in mind this will evaluate the whole expression first and then filter it. This use IMHO is best with shared datasets that are rather small and fast. Or you can use the filter clause in tablix elements as well which often is good when you want three objects from the same set but different predicates evaluated after runtime but to limit scope with reuse of one dataset for many objects.
I have problems making a SQL request.
Here is my tables:
CREATE TABLE dates(
id INT PRIMARY KEY,
obj_id INT,
dispo_date text
);
CREATE TABLE option(
id INT PRIMARY KEY,
obj_id INT,
random_option INT
);
CREATE TABLE obj(
id INT PRIMARY KEY,
);
and a random date that the user gives me and some options.
I'd like to select everything on both tables which correspond to an obj having his date equal to the user's date.
let's say that DATE = "22/01/2013" and OPTIONS = 3.
SELECT * FROM obj
INNER JOIN dates
ON dates.obj_id=obj.id
INNER JOIN option
ON option.obj_id=obj.id
WHERE dates.dispo_date="22/01/2013"
AND option.random_option=3;
That just gives me everything from my obj table with, for each one, the same dates and options without filtering anything.
Can someone give me some pointers about what I'm doing wrong ?
SOLUTION:
Since everybody seemed to get what I was looking for I restarted my SQL server and since, everything works ...
Thanks for your help and sorry for the time-loss :-(
As far as I can see, there is nothing wrong with the query.
When I try it, it returns only the obj rows where there is a corresponding date and a corresponding option.
insert into dates values
(1, 1, '22/01/2013'),
(2, 1, '23/01/2013'),
(3, 2, '22/01/2013'),
(4, 2, '23/01/2013'),
(5, 3, '23/01/2013'),
(6, 3, '24/01/2013');
insert into `option` values
(1, 1, 4),
(2, 1, 5),
(3, 2, 3),
(4, 2, 4),
(5, 3, 3),
(6, 3, 4);
insert into obj values
(1),
(2),
(3)
With this data it should filter out obj 1 because there is no option 3 for it, and filter out obj 3 because there is no date 22 for it.
Result:
ID OBJ_ID DISPO_DATE RANDOM_OPTION
-------------------------------------
2 2 22/01/2013 3
Demo: http://sqlfiddle.com/#!2/a398f/1
Change your line
WHERE dates.dispo_date="22/01/2013"
for
WHERE DATE(dates.dispo_date)="22/01/2013"
Handling dates in text fields is a little tricky (also bad practice). Make sure both dates are in the same format.
First, I'm a little confused on which ID's map to which tables. I might respectfully suggest that the id field in DATES be renamed to date_id, the id in OPTION be renamed to option_id, and the id in obj to obj_id. Makes those relationships MUCH clearer for folks looking in through the keyhole. I'm going in a bit of a circle making sure I understand your relationships properly. On that basis, I may be understanding your problem incorrectly.
I think you have obj.id->dates.obj_id, and option.obj_id->dates.obj_id, so on that basis, I think your query has to be a bit more complicated:
This gives you object dates:
Select *
from obj obj
join dates d
on obj.id=d.obj_id
This gives you user dates:
select *
from option o
join dates d
on o.obj_id=d.obj_id
To get the result of objects and users having the same dates, you'd need to hook these two together:
select *
from (Select *
from obj obj
join dates d
on obj.id=d.obj_id) a
join (select *
from option o
join dates d
on o.obj_id=d.obj_id) b
on a.dispo_date=b.dispo_date
where b.random=3
I hope this is useful. Good luck.