I have two models PrintEvent and SocialEvent with 2 tables as given below:-
print_events:-
╔════╤════════════════════════╤════════════╗
║ id │ name │ date ║
╠════╪════════════════════════╪════════════╣
║ 1 │ Important print event1 │ 01/05/2015 ║
╟────┼────────────────────────┼────────────╢
║ 2 │ Important print event2 │ 02/05/2015 ║
╟────┼────────────────────────┼────────────╢
║ 3 │ Important print event3 │ 03/05/2015 ║
╚════╧════════════════════════╧════════════╝
social_events:-
╔════╤═════════════════════════╤════════════╗
║ id │ name │ date ║
╠════╪═════════════════════════╪════════════╣
║ 1 │ Important social event1 │ 01/05/2015 ║
╟────┼─────────────────────────┼────────────╢
║ 2 │ Important social event2 │ 02/05/2015 ║
╟────┼─────────────────────────┼────────────╢
║ 3 │ Important social event3 │ 03/05/2015 ║
╚════╧═════════════════════════╧════════════╝
Now I have a search form with 'event date from' and 'event date to' fields and want to show the list of records from both tables using one model or any other way to achieve this but don't want to use separate queries using both models.
Thanks.
Without relation between the tables? Then you just have to do 2 queries instead.
or just do:
class yourFirstModel extends AppModel{
$public $hasMany = array('secondModel');
}
Then
class secondModel extends AppModel{
$public $belongTo = array('yourFirstModel');
}
And when you query any of these Models you should be able to get data from both tables.
Ok, here is another way of using join if you do not want to use my first approach.
You modify the query to meet your own specification.
$this->PrintEvent->find('all', array(
'joins' => array(
array(
'table' => 'social_events',
'alias' => 'EventJoin',
'type' => 'INNER',
'conditions' => array(
'EventJoin.date = PrintEvent.date'
)
)
),
'conditions' => array(
'PrintEvent.date' => $searchConditions
),
'fields' => array('EventJoin.*', 'PrintEvent.*'),
'order' => 'PrintEvent.date DESC'
));
Note that this has to be in your controller.
Let me know if this help.
As far as I understand CakePHP models can only ever represent one table each. You may need to resort to using query() to preform the UNION SQL:-
$this->PrintEvent->query('SELECT id, name, date FROM print_events UNION SELECT id, name, date FROM social_events');
I would normally advise against using this method, but I believe what you are trying to achieve is not supported by the framework directly.
Related
I am not completely new to SQL, but this time I am slow on the uptake.
For a data export, I have to select some user data including two JOINs. The data is not related, I just need both information in one export sheet.
I have created a example. The column groupname is from one JOIN and the column course from the other JOIN:
╔════╦═══════════╦══════════╦═══════════╦════════════╗
║ id ║ firstname ║ lastname ║ groupname ║ course ║
╠════╬═══════════╬══════════╬═══════════╬════════════╣
║ 1 ║ John ║ Doe ║ Manager ║ Management ║
║ 1 ║ John ║ Doe ║ CEO ║ Management ║
║ 1 ║ John ║ Doe ║ Manager ║ Logistics ║
║ 1 ║ John ║ Doe ║ CEO ║ Logistics ║
║ 1 ║ John ║ Doe ║ Manager ║ Leadership ║
║ 1 ║ John ║ Doe ║ CEO ║ Leadership ║
╚════╩═══════════╩══════════╩═══════════╩════════════╝
Due to the nature of JOINS; the groupname-column is duplicated now several times. But what I actually want, is something like this:
╔════╦═══════════╦══════════╦═══════════╦════════════╗
║ id ║ firstname ║ lastname ║ groupname ║ course ║
╠════╬═══════════╬══════════╬═══════════╬════════════╣
║ 1 ║ John ║ Doe ║ Manager ║ ║
║ 1 ║ John ║ Doe ║ CEO ║ ║
║ 1 ║ John ║ Doe ║ ║ Management ║
║ 1 ║ John ║ Doe ║ ║ Logistics ║
║ 1 ║ John ║ Doe ║ ║ Leadership ║
╚════╩═══════════╩══════════╩═══════════╩════════════╝
I guess, doing two SELECT-Statements consecutively would be the better option. Unfortunately, the original query with JOINS and where-Arguments has like 25 lines of code, so I would not like to duplicate it.
Is there a way to achieve my way of output more easily then doing for example a UNION with two long queries (see below for simple example in this case)?
SELECT u.[id]
,[firstname]
,[lastname]
,groupname
,'' AS course
FROM [dbo].[users] u
JOIN dbo.groups g ON u.id = g.userId
UNION ALL
SELECT u.[id]
,[firstname]
,[lastname]
,'' AS groupname
,course
FROM [dbo].[users] u
JOIN dbo.courses c ON u.id = c.userId
You could create a Table-Valued UDF with the query in question and then make a UNION ALL with the two UDFs
Pro:
- Much shorter Query:
SELECT * FROM [MY_UDF](Param 1, Param 2, ...)<br/>
UNION ALL<br/>
SELECT * FROM [MY_UDF](Different Param 1, Different Param 2, ...)
Con:
- You have to create the table valued UDF.
Otherwise: I think QUERY_1 UNION ALL QUERY_2 is probably the way to go.
I think their is a lot of way to solve your problem. I will give you the best way I can think of.
First Solution : Simply use a WITH not to repeat your common part query as follow:
WITH CommonPart (id, firstname, lastname)
AS
(
Select id, firstname, lastname
From [dbo].[users]
-- Eventually a filter ...
)
SELECT cp.*
, g.groupname
, '' AS course
FROM CommonPart cp
JOIN dbo.groups g ON cp.id = g.userId
UNION ALL
SELECT cp.*
,'' AS groupname
,c.course
FROM CommonPart cp
JOIN dbo.courses c ON cp.id = c.userId
Second Solution : You can Insert null values into courses and groups and use a simple LEFT JOIN. But I don't like this second solution.
EDIT: After Insert of null values, it would look like:
Select u.id,
u.firstname,
u.lastname,
g.groupname,
c.course
From [dbo].[users] u
Left Join [dbo].[groups] g ON g.userId = u.id
Left Join [dbo].[courses] c ON c.userId = u.id
Where (g.groupname IS NULL and c.course IS NOT NULL)
OR (g.groupname IS NOT NULL and c.course IS NULL)
I have a table Users,
╔════╦═══════╦══════╗
║ Id ║ Name ║ Db ║
╠════╬═══════╬══════╣
║ 1 ║ Peter ║ DB1 ║
║ 2 ║ John ║ DB16 ║
║ 3 ║ Alex ║ DB23 ║
╚════╩═══════╩══════╝
and many databases that have the same structure (Same tables, same procedures, ...), so every database have a table named Project, and this is the structure of Project table,
╔════╦═════════╦═════════════╗
║ Id ║ Request ║ Information ║
╠════╬═════════╬═════════════╣
║ 1 ║ 126 ║ XB1 ║
║ 2 ║ 126 ║ D6 ║
║ 3 ║ 202 ║ BM-23 ║
╚════╩═════════╩═════════════╝
So, when I query a database :
SELECT count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB1].[dbo].[Project]
I get this result :
╔═════════════╗
║ NbrRequests ║
╠═════════════╣
║ 2 ║
╚═════════════╝
Now, what I want is to "link"/"join" ... results from the table Users to this query, where the column Db in Users table is the name of my database, so I can get a result like this :
╔════╦═══════╦══════╦═════════════╗
║ Id ║ Name ║ Db ║ NbrRequests ║
╠════╬═══════╬══════╬═════════════╣
║ 1 ║ Peter ║ DB1 ║ 2 ║
║ 2 ║ John ║ DB16 ║ 3 ║
║ 3 ║ Alex ║ DB23 ║ 6 ║
╚════╩═══════╩══════╩═════════════╝
I'm trying with dynamic SQL, but no luck.
NB : Every user has only one database, and a database belong to only one user, it's one-to-one relationship
The way you can do it is with a UNION counting every specific database table and giving it a identification for the database, like this:
SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests
FROM [Users] u INNER JOIN
(SELECT 'DB1' as db, count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB1].[dbo].[Project]
UNION
SELECT 'DB16', count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB16].[dbo].[Project]
UNION
SELECT 'DB23', count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB23].[dbo].[Project]
) dbCts ON u.Db = dbCts.db
Don't forget to add the server and schema to the Users table I didn't because there is no such info on your question.
Also in order to do this, your connected user must have privileges on all databases.
Dynamic SQL can be very tricky.
This example builds the select query from the users table. The variable #Query is incremented for each line returned by the Users table. Each row returns a query that joins the local users table to the projects table in a remote db. The results of each query are UNIONED together.
Example
-- Wil holds our dynamic query.
DECLARE #Query NVARCHAR(MAX) = '';
-- Builds our dynamic statement.
SELECT
#Query =
#Query
+ CASE WHEN LEN(#Query) > 0 THEN ' UNION ALL ' ELSE '' END
+ 'SELECT u.Id, u.Name, u.Db, COUNT(DISTINCT p.Request) AS NbrRequest '
+ 'FROM [SVR02].' + QUOTENAME(DB) + 'dbo.Project AS p INNER JOIN Users u ON u.Db= p.Db '
+ 'GROUP BY u.Id, u.Name, u.Db'
FROM
Users
;
-- Executes the dynamic statement.
EXECUTE (#Query);
This example uses QUOTENAME to help avoid SQL injection attacks.
Combining these 2 answers https://stackoverflow.com/a/35795690/1460399 and https://stackoverflow.com/a/35795189/1460399, I got this solution :
DECLARE #Query NVARCHAR(MAX)= 'SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests FROM [Users] u INNER JOIN (';
DECLARE #QueryLength INT= LEN(#Query);
SELECT #Query = #Query
+CASE WHEN LEN(#Query) > #QueryLength THEN ' UNION ' ELSE '' END
+'SELECT '''+Db+''' as db, count(distinct(Request)) as nbrRequests FROM [SRV02].'+Db+'[Project]'
FROM Users;
SET #Query = #Query+') dbCts ON u.Db = dbCts.db';
EXECUTE (#Query);
I have a full text search catalog and index set up on my table.
I first tried to run the query below with only one row in the table and it worked by returning the row I was looking based on the string 'test'. But when I placed a second row into the table it still only returned one row, not two rows. I'm trying to get it to return more then one row and I'm not sure why it's not. Any help would be appreciated.
Query's attempted
SELECT *
FROM dbo.Gifts
WHERE CONTAINS(Name, 'test')
SELECT *
FROM dbo.Gifts
WHERE CONTAINS(Name, '"test gift"')
SELECT *
FROM dbo.Gifts
WHERE FREETEXT (Name, 'test gift')
SELECT *
FROM dbo.Gifts
WHERE FREETEXT(Name, 'test')
and here are the two rows in the table
╔════════╦════════════╦════════╦════════╦═════════╦══════════════╦═══════════╗
║ GiftId ║ Name ║ Rating ║ Status ║ OwnerId ║ Availability ║ Thumbnail ║
╠════════╬════════════╬════════╬════════╬═════════╬══════════════╬═══════════╣
║ 1 ║ test gift ║ 5 ║ 0 ║ 1 ║ 0 ║ NULL ║
║ 2 ║ test gift1 ║ 2 ║ 0 ║ 1 ║ 0 ║ NULL ║
╚════════╩════════════╩════════╩════════╩═════════╩══════════════╩═══════════╝
Only the first row is being returned with giftid = 1 and I want both rows to be returned.
I have three tables that hold data on physicians and the practices and health care organizations they belong to. For example ..
[Table Hmo]
╔════╦════════════════════════════════════╗
║ Id ║ Name ║
╠════╬════════════════════════════════════╣
║ 1 ║ Purple Cross and Yellow Shield HMO ║
║ 2 ║ Tifts Health HMO ║
╚════╩════════════════════════════════════╝
[Table Practices]
╔════╦═══════╦═════════════════════════╗
║ Id ║ HmoId ║ Name ║
╠════╬═══════╬═════════════════════════╣
║ 1 ║ 1 ║ Downtown Cardiac Group ║
║ 2 ║ 1 ║ Tropical Medicine Group ║
║ 3 ║ 2 ║ Action SportsMed Group ║
╚════╩═══════╩═════════════════════════╝
[Table Physicians]
╔════╦═══════╦════════════╦══════════════════╗
║ Id ║ HmoId ║ PracticeId ║ Name ║
╠════╬═══════╬════════════╬══════════════════╣
║ 1 ║ ? ║ 1 ║ Dr. Trapper-John ║
║ 2 ║ ? ║ 1 ║ Dr. Doolittle ║
║ 3 ║ ? ║ 2 ║ Dr. Smith ║
║ 4 ║ ? ║ 3 ║ Dr. Flintstone ║
╚════╩═══════╩════════════╩══════════════════╝
I know the HmoId column is not necessary because the tables are linked by foreign keys, however, the user would neverthless still like to have this column populated. What I can't figure out is how to populate the HmoId column using an update query.
I can write a query to obtain the HmoId for each physician ...
SELECT Physicians.Name, Hmo.Name
FROM Physicians
LEFT JOIN Practices ON Physicians.PracticeId = Practices.Id
LEFT JOIN Hmo ON Practices.HmoId = Hmo.Id
But how to translate that to an update query eludes me.
Update p set
p.hmoid = h.id
FROM Physicians p
LEFT JOIN Practices pr ON pr.id = p.practiceid
LEFT JOIN Hmo h ON h.id = pr.HmoId
I need to create a concatenated column based on two other columns in the table. One column is the year (10 distinct values), and one is a person's ID value (~150,000 distinct values). This is being used as a business key by an ETL task that will not accept multiple columns as the key value, so I need to persist this value in my database.
That said, I can choose how to create that value, and I'm wondering if the order (ID + Year or Year + ID) affects performance in any way. If the year goes first, the first four characters will always be one of a limited set of actual years. If the ID goes first, that will change for each user. Is there any difference between the two?
The only usage this column will get is during the ETL load, where it will be used to join data from the source and staging tables to check for differences between the two. The base values will be in the table underneath, and I plan on creating a clustered index on those base values.
Sample Data:
╔══════════════╦══════════════╦═════════╦═════════╗
║ COMPOSITE_1 ║ COMPOSITE_2 ║ AC_YEAR ║ ST_ID ║
╠══════════════╬══════════════╬═════════╬═════════╣
║ 0000001|2005 ║ 2005|0000001 ║ 2005 ║ 0000001 ║
║ 0000001|2006 ║ 2006|0000001 ║ 2006 ║ 0000001 ║
║ 0000001|2009 ║ 2009|0000001 ║ 2009 ║ 0000001 ║
║ 0000001|2010 ║ 2010|0000001 ║ 2010 ║ 0000001 ║
║ 0000001|2012 ║ 2012|0000001 ║ 2012 ║ 0000001 ║
║ 0000001|2013 ║ 2013|0000001 ║ 2013 ║ 0000001 ║
║ 0000002|2005 ║ 2005|0000002 ║ 2005 ║ 0000002 ║
║ 0000002|2006 ║ 2006|0000002 ║ 2006 ║ 0000002 ║
║ 0000002|2007 ║ 2007|0000002 ║ 2007 ║ 0000002 ║
║ 0000002|2008 ║ 2008|0000002 ║ 2008 ║ 0000002 ║
║ 0000002|2009 ║ 2009|0000002 ║ 2009 ║ 0000002 ║
║ 0000002|2010 ║ 2010|0000002 ║ 2010 ║ 0000002 ║
║ 0000002|2012 ║ 2012|0000002 ║ 2012 ║ 0000002 ║
║ 0000002|2013 ║ 2013|0000002 ║ 2013 ║ 0000002 ║
║ 0000002|2014 ║ 2014|0000002 ║ 2014 ║ 0000002 ║
╚══════════════╩══════════════╩═════════╩═════════╝
Question One: would either Composite_1 or Composite_2 give me better performance during the JOIN?
Question Two: would I ever need to index the Composite column, and if so should I do it alone/with others? The SSIS task will be using it for an in-memory JOIN, and I plan to include it as an ORDER BY within my OLE DB Source component.
Question Three: Does the clustered index belong on the Composite column, or the Year and ID columns? EDIT: Or, since I know that Year and ID won't affect the order of Composite, should I just include all three?
Since you're turning these into a string column, the index is going to order them based on the characters in the string. You'll want the field (year or id) with the best distribution and most unique values to be first.
You should index the composite column since it's being used for the join. Whether you want to include other data depends on what data you are pulling back.
If you don't need the clustered index on any other columns, and the table is only being used for BI/data warehouse loading, you may as well put it on the composite column. That way a key lookup won't be required to get any other data you may need.